TypeScript 型別整理

TypeScript, GraphQL, gRPC 型別整理

最近很常用到 TypeScript, GraphQL, gRPC,有時候寫 code 寫了一整天實在很容易混淆,決定來稍微整理一下這三個工具的型別。

1. TypeScript

1.1 常用型別

// string
const testString: string = 'Hello world';

// number
const testNumber: number = 10;
const testFloat: number = 10.5;

// boolean
const testBoolean: boolean = true;

// null
const testNull: null = null;

// undefined
const testUndefined: undefined = undefined;

// array
const testArray1: number[] = [1, 2, 3];
const testArray2: string[] = ['apple', 'banana', 'orange'];
const testArray3: Array<number> = [1, 2, 3];
const testArray4: Array<string> = ['apple', 'banana', 'orange'];

// object
// ? 代表非必要 property ; 屬性之間用 ',' 或 ';' 隔開都可以
const testObj1: {name: string, age: number} = {name: 'Jimmy', age: 18};
const testObj2: {name: string; age?: number} = {name: 'Jimmy'};

// any
const testAny: any = ['apple', 5, {name: 'Jimmy'}]

// function
// 在變數的 () 後面指定要 return 的 type
const testFunction = (num: number): string => {
  return `${num} apple`
}
testFunction(5);

// union types
let testUnion: string | number = 5;
testUnion = 'Jimmy';
testUnion = 5;

1.2 Type Aliases ( 型別化名 )

// type aliases
type ID = string | number;
const id1: ID = '1';
const id2: ID = 2;

type TypeArr = number[];
const typeArr: TypeArr = [1, 2, 3];

type TestObject1 = {
  name: string,
  age: number,
  isAdult?: boolean
}

const testObject: TestObject1 = {
  name: 'Jimmy',
  age: 18,
  isAdult: true
}

const testArray: TestObject1[] = [
  {
    name: 'Jimmy',
    age: 18,
    isAdult: true
  },
  {
    name: 'Sandy',
    age: 18
  }
]

type TestObject2 = TestObject1 & {
  address: string
}

const testObject2: TestObject2 = {
  name: 'Jimmy',
  age: 18,
  isAdult: true,
  address: 'Taipei'
}

1.3 Interfaces

// interfaces
interface IDInterface = string | number;
interface ArrInterface = number[];
// error! interfaces 只能指定 object 的型別

interface TestInterface1 {
  name: string
}

interface TestInterface2 extends TestInterface1 {
  age: number
}

const testInterface1: TestInterface1 = {
  name: 'Jimmy'
}

const testInterface2: TestInterface2 = {
  name: 'Jimmy',
  age: 18
}

interface DuplicateInterface {
  name: string
}

interface DuplicateInterface {
  age: number
}

const duplicateInterface1: DuplicateInterface = {
  name: 'Jimmy'
}
// error ! DuplicateInterface 現在的型別是:{name: string, age: number}

const duplicateInterface2: DuplicateInterface = {
  name: 'Jimmy',
  age: 18
}

1.4 Type Aliases 和 Interfaces 的差別

  • Interfaces 只能指定 object 的型別,type aliases 可以指定任意型別
  • Interfaces 可以用 extends 繼承其他 interfaces ,type aliases 用 ‘&’ (交集) 來達到類似的功能
  • 重複宣告一樣的 interface 時,interface 會自動繼承原本同名的型別,type aliases 重複宣告一樣名字時則會 throw error

1.5 Enums ( 列舉、枚舉 )

// numeric enums
enum Direction1 {
  Up = 1,
  Down,
  Left,
  Right,
}
console.log(Direction1);
/*
{
  '1': 'Up',
  '2': 'Down',
  '3': 'Left',
  '4': 'Right',
  Up: 1,
  Down: 2,
  Left: 3,
  Right: 4
}
*/

enum Direction2 {
  Up,
  Down,
  Left,
  Right,
}
console.log(Direction2);
/*
{
  '0': 'Up',
  '1': 'Down',
  '2': 'Left',
  '3': 'Right',
  Up: 0,
  Down: 1,
  Left: 2,
  Right: 3
}
*/

// string enums
enum Direction3 {
  Up = 'UP_string',
  Down = 'Down_string',
  Left = 'Left_string',
  Right = 'Right_string',
}

console.log(Direction3)
/*
{
  Up: 'UP_string',
  Down: 'Down_string',
  Left: 'Left_string',
  Right: 'Right_string'
}
*/
// iteration of numeric enum
for(const value in Direction1) {
  console.log(value);
}
/*
1
2
3
4
Up
Down
Left
Right
*/


for(const value in Direction1) {
  console.log(Direction1[value]);
}
/*
Up
Down
Left
Right
1
2
3
4
*/

for(const value in Direction1) {
  if (isNaN(Number(value))) {
    console.log(value);
  }
}
/*
Up
Down
Left
Right
*/

// iteration of string enum
for(const value in Direction3) {
  console.log(value);
}
/*
Up
Down
Left
Right
*/

for(const value of Object.values(Direction3)) {
  console.log(value);
}
/*
UP_string
Down_string
Left_string
Right_string
*/

const keys: (keyof typeof Direction3)[] = <(keyof typeof Direction3)[]>Object.keys(Direction3);
console.log(keys);
// [ 'Up', 'Down', 'Left', 'Right' ]
for (const key of keys) {
  const direction3_string: string = Direction3[key];
  console.log(direction3_string);
}
/*
UP_string
Down_string
Left_string
Right_string
*/

1.6 Type Assertion ( 型別斷言 )

function printId(id: number | string) {
  if (id.length) {
    console.log(id.length)
  } else {
    console.log(id.toString().length)
  }
}
// error!! Property 'length' does not exist on type 'string | number'.
// Property 'length' does not exist on type 'number'.

function printId(id: number | string) {
  if ((<string>id).length) {
    console.log((<string>id).length)
  } else {
    console.log(id.toString().length)
  }
}

printId('Jimmy')
// 5
printId(10);
// 2

let file = {}
file.name = 'Jimmy';

// error: Property 'name' does not exist on type '{}'.
file.age = 18
// error: Property 'name' does not exist on type '{}'

type FileType = {
  name: string,
  age: number
}
let file = <FileType> {}
// or let file = {} as FileType
file.name = 'Jimmy';
file.age = 18

2. GraphQL

type Person {
  id: ID!
  # 宣告為 ID 的欄位可以輸入 String 或是 Int,但最後都會被轉為 String
  # ! 代表此欄位必填
  name: String
  age: Int
  isAdult: Boolean
  weight: Float
  childrenName: [String]
}

# input 代表要在 request 帶的變數的型別
input PersonConfig {
  id: ID!
}

3. gRPC

// gRPC.proto
message UserConfigRequest {
  int32 id = 1;
}

message CarInfo {
  string brand = 1;
  int32 horsepower = 2;
  bool isTurbo = 3;
}

message UserResponse {
  string name = 1;
  int32 age = 2;
  sint32 property = 3;
  bool isAdult = 4;
  float weigth = 5;
  repeated CarInfo cars = 6;
  repeated string childrenName = 7;
}

/* example for UserResponse
{
  name: 'Jimmy',
  age: 18,
  property: -10000,
  isAdult: true,
  weight: 75.5,
  cars: [
    { brand: 'Ford', horsepower: 180 },
    { brand: 'Mazada', horsepower: 150, isTurbo: false}
  ],
  children: ['Jenny', 'Tommy']
}
*/

service UserService {
  rpc UserData(UserConfigRequest) returns (UserResponse);
}

4. 參考資料

TypeScript:
TypeScript: Documentation – Everyday Types
Iterating a TypeScript Enum – Peter Morlion
TypeScript | 善用 Enum 提高程式的可讀性 – 基本用法 feat. JavaScript
Type Assertion in TypeScript

GraphQL:
Schemas and Types | GraphQL
學習 GraphQL 筆記(一)Object Type

gRPC:
Protocol Buffers  |  Google Developers

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top