### 型別的聯集(union)運算

```const o1: { a: number } = { a: 1, b: "2" };
const o2: { b: string } = { a: 1, b: "2" };```

```const o = { a: 1, b: "2" };
const o1: { a: number } = o;

const o2: { b: string } = { a: 1, b: "2" } as { b: string };```

```const a = [1, "2", false];
const a1: [number, string] = a; // compilation Error

const a2: [number, string] = a as [number, string];```

```const o1: { a: number } = { a: 1, b: "2" };
const o2: { b: string } = { a: 1, b: "2" };```

`const o: { a: number } | { b: string } = { a: 1, b: "2" };`

```const o: { a: number } | { b: string } = { a: 1, b: "2" };

const oa = o as { a: number };

console.log(oa.a);

const ob = o as { b: string };

console.log(ob.b);```

### 型別的交集(intersection)運算

```const o: { a: number } & { b: string } = { a: 1, b: "2" };

console.log(o.a);
console.log(o.b);```

### 型別的群組

`const a: string | number[] = ["I am a string."];`

`const a: string[] | number[] = ["I am a string."];`

`const a: (string | number)[] = ["I am a string."];`

### 型別的別名

```type A = { a: number };
type B = { b: string };

type AB = A | B;

const o: AB = { a: 1, b: "2" };

const oa = o as A;

console.log(oa.a);

const ob = o as B;

console.log(ob.b);```

`type MyType<T> = T | undefined;`

### 型別的條件運算

`type A<T, K> = T extends K ? number : string;`

### 用來做型別運算的TypeScript內建型別

#### Exclude

`Exclude`定義如下：

`type Exclude<T, U> = T extends U ? never : T;`

#### Extract

`Extract`定義如下：

`type Extract<T, U> = T extends U ? T : never;`

#### NonNullable

`NonNullable`定義如下：

`type NonNullable<T> = T extends null | undefined ? never : T;`

#### ReturnType

`ReturnType`定義如下：

`type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any;`

#### InstanceType

`InstanceType`定義如下：

`type InstanceType<T extends new (...args: any) => any> = T extends new (...args: any) => infer R ? R : any;`

### 複製值的型別

```let foo = 123;
let bar: typeof foo;```

`typeof`關鍵字用在型別上時，其後只能夠接上有在TypeScript程式中被定義的名稱或是路徑，無法直接使用定數或是表達式。

```class Foo {
foo = 0;
}

declare let _foo: Foo;

let bar: typeof _foo.foo;```

```const foo = "Hello World";

let bar: typeof foo;

bar = "Hello World";
bar = "something else"; // compilation Error```

### 複製鍵值的型別

```class F {

constructor(name: string, age: number, studentNumber?: string) {
this.name = name;
this.age = age;
this.studentNumber = studentNumber;
}

toString() {
return `\${this.name}: \${this.age}`;
}
}

const o = new F("David", 18);

type FKey = keyof typeof o;

let key: FKey;

key = "name";
key = "age";
key = "studentNumber";
key = "toString";```

```const o = [1, 3, 5, 7];

let key: keyof typeof o;

key = "length";
key = 1;
key = 2;
key = 3;
key = 4;```

### 指定Node.js的`require`函數回傳的型別

```const isBrowser: boolean = typeof window === "object";

function showMessage(text: string): void {
if (isBrowser) {
} else {
console.log(text);
}
}

async function showMessageAndInputText(text: string): Promise<string | null> {
if (isBrowser) {
return prompt(text);
} else {
console.log(text);

const rl = readline.createInterface({ input: process.stdin });

const lineResolver: Promise<string> = new Promise<string>(resolve => {
rl.on("line", (line: string) => resolve(line));
});

const line: string = await lineResolver;

rl.close();

return line;
}
}

async function main(): Promise<void> {
showMessage("Guess the number!");

const secretNumber: number = Math.floor(Math.random() * 100 + 1);

showMessage(`The secret number is: \${secretNumber}`);

while (true) {

if (line === null) {
continue;
}

const guess: number = parseInt(line);

if (isNaN(guess)) {
} else {
showMessage(`You guessed: \${guess}`);

if (guess < secretNumber) {
showMessage("Too small!");
} else if (guess > secretNumber) {
showMessage("Too big!");
} else {
showMessage("You win!");
break;
}
}
}
}

main();```

```import readline = require("node:readline");

const isBrowser: boolean = typeof window === "object";

function showMessage(text: string): void {
if (isBrowser) {
} else {
console.log(text);
}
}

async function showMessageAndInputText(text: string): Promise<string | null> {
if (isBrowser) {
return prompt(text);
} else {
console.log(text);

const rl = readline.createInterface({ input: process.stdin });

const lineResolver: Promise<string> = new Promise<string>(resolve => {
rl.on("line", (line) => resolve(line));
});

const line: string = await lineResolver;

rl.close();

return line;
}
}

async function main(): Promise<void> {
showMessage("Guess the number!");

const secretNumber: number = Math.floor(Math.random() * 100 + 1);

showMessage(`The secret number is: \${secretNumber}`);

while (true) {

if (line === null) {
continue;
}

const guess: number = parseInt(line);

if (isNaN(guess)) {
} else {
showMessage(`You guessed: \${guess}`);

if (guess < secretNumber) {
showMessage("Too small!");
} else if (guess > secretNumber) {
showMessage("Too big!");
} else {
showMessage("You win!");
break;
}
}
}
}

main();```

`import`關鍵字寫進`showMessageAndInputText`函數中是鐵定行不通的，因為`import`關鍵字必須要寫在程式最外層。

```import _readline = require("node:readline");

const isBrowser: boolean = typeof window === "object";

function showMessage(text: string): void {
if (isBrowser) {
} else {
console.log(text);
}
}

async function showMessageAndInputText(text: string): Promise<string | null> {
if (isBrowser) {
return prompt(text);
} else {
console.log(text);

const rl = readline.createInterface({ input: process.stdin });

const lineResolver: Promise<string> = new Promise<string>(resolve => {
rl.on("line", (line) => resolve(line));
});

const line: string = await lineResolver;

rl.close();

return line;
}
}

async function main(): Promise<void> {
showMessage("Guess the number!");

const secretNumber: number = Math.floor(Math.random() * 100 + 1);

showMessage(`The secret number is: \${secretNumber}`);

while (true) {

if (line === null) {
continue;
}

const guess: number = parseInt(line);

if (isNaN(guess)) {
} else {
showMessage(`You guessed: \${guess}`);

if (guess < secretNumber) {
showMessage("Too small!");
} else if (guess > secretNumber) {
showMessage("Too big!");
} else {
showMessage("You win!");
break;
}
}
}
}

main();```

`import`關鍵字還有很多功能，會在之後的章節詳細介紹。另外，注意這邊的`import`關鍵字用法會導致TypeScript程式無法在編譯目標設為`ES6`或以上時成功編譯，我們在之後的章節介紹到模組時會順便解決這個問題。

### 函數的轉型

```const o: { f1: number, f2: string } = {
f1: 1,
f2: "2",
};

const oo: { f1: number } = o;

const f: (o: { f1: number, f2: string }) => void = (o: { f1: number, f2: string }) => {
};

const ff: (o: { f1: number }) => void = f;

const fff: (o: { f1: number }) => void = (o: { f1: number, f2: string }) => {
};```

```const o: { f1: number, f2: string } = {
f1: 1,
f2: "2",
};

const oo: { f1: number } = o;

const f: () => { f1: number, f2: string } = () => ({
f1: 1,
f2: "2",
});

const ff: () => { f1: number } = f;

const fff: () => { f1: number } = () => ({
f1: 1,
f2: "2",
});```

```const f1: () => void = () => undefined;
const f2: () => void = () => 1;
const f3: () => void = () => "2";
const f4: () => void = () => false;
const f5: () => void = () => ({ f1: 1, f2: "2" });```

```const o: { f1: number, f2: string } = {
f1: 1,
f2: "2",
};

const oo: { f1: number } = o;

const f: (o: { f1: number, f2: string }) => void = (o: { f1: number, f2: string }) => {
};

const ff: (o: { f1: number, f2: string, f3: boolean }) => void = f;

const fff: (o: { f1: number, f2: string, f3: boolean }) => void = (o: { f1: number, f2: string }) => {
};```

### 特殊的物件屬性

TypeScript的物件型別預設了幾個擁有特殊功能的「屬性」。

#### 可被呼叫的物件型別

```const f: (n: number) => number = function (n: number) {
return n + 1;
};```

```const f: { (n: number): number } = function (n: number) {
return n + 1;
};```

```const f: { (n: number): number, f1?: number, f2?: string } = function (n: number) {
return n + 1;
};

f.f1 = 1;
f.f2 = "2";

console.log(f.f1);
console.log(f.f2);
console.log(f(100));```

1
2
101

#### 可被「new」的物件型別

```function F(this: { t: number }, n: number) {
this.number = n;
}

const a = new (F as any)();

console.log(a.t);```

```const F: { new(n: number): { t: number } } = function (this: { t: number }, n: number) {
this.t = n;
} as any;

const a = new F(1);

console.log(a.t);```

#### 有多載的物件方法

```const o: { name: string, age: number, studentNumber: string, toString: () => string } = {
name: "David",
age: 18,
studentNumber: "B12345678",
toString: function () {
return `\${this.age}: \${this.name}`;
},
};```

```const o: { name: string, age: number, studentNumber: string, toString(): string } = {
name: "David",
age: 18,
studentNumber: "B12345678",
toString: function () {
return `\${this.age}: \${this.name}`;
},
};```

```const o: { name: string, age: number, studentNumber: string, toString(): string, toString(includeStudentNumber: boolean): string } = {
name: "David",
age: 18,
studentNumber: "B12345678",
toString: function (includeStudentNumber?: boolean) {
if (includeStudentNumber) {
return `\${this.name}: \${this.age}, \${this.studentNumber}`;
}
return `\${this.name}: \${this.age}`;
},
};```