---
# System prepended metadata

title: Ess

---

# Essential TypeScript Ch8 Function

## 定義函式
### 重複定義
```typescript
function calculateTax(amount) {
  return amount * 1.2;
}

function calculateTax(amount, discount) {
  return calculateTax(amount) - discount;
}
```
JS不支援函式多載，後面會覆蓋前面
第一個定義被忽略了，呼叫的是第二個

### 合併函式
```typescript
function calculateTax(amount, discount) {
  return (amount * 1.2) - discount;
}
let taxValue = calculateTax(100, 0);
// => 120
```

### 參數數量
```typescript
let taxValue = calculateTax(100); // 太少
let taxValue = calculateTax(100, 0, 1); // 太多
```

### 選擇性參數
```typescript
function calculateTax(amount, discount?) {
  return (amount * 1.2) - (discount || 0);
}
// 必須放在後面
let taxValue = calculateTax(100); // discount = undefined
let taxValue = calculateTax(100, 10); // discount = 10
```

### 預設參數
```js
function calculateTax(amount, discount = 0) {
  return (amount * 1.2) - discount;
}
let taxValue = calculateTax(100); // discount = 0
let taxValue = calculateTax(100, 10); // discount = 10
```

### 其餘參數 Rest Parameter
```js
function calculateTax(amount, discount = 0, ...extraFees) {
  return (amount * 1.2) - discount
	    + extraFees.reduce((total, val) => total + val, 0);
}
// typeof extraFees == Array
let taxValue = calculateTax(100, 20, 9, 8); // taxValue = 117
```

### 參數套用型別註記
- TS預設所有參數為any型別
- 使用註記來宣告成特定型別
```typescript
function calculateTax(amount: number, discount: number = 0, ...extraFees: number[]) {
  return (amount * 1.2) - discount
	    + extraFees.reduce((total, val) => total + val, 0);
}
function calculateTax(amount: number, discount?: number, ...extraFees: number[]) {
  return (amount * 1.2) - discount
	    + extraFees.reduce((total, val) => total + val, 0);
}
// 寫在參數後面, 預設值前面
let taxValue = calculateTax(100, 20, 9, 8); // taxValue = 117
```

### 控制null參數
```typescript

let taxValue = calculateTax(null, 20); // taxValue = -20
/*
null被乘法強制轉型為0, 結果也為0
null被系統吃掉了, 或許合理但難以除錯
"strictNullChecks": true (禁止將null, undefined指派給所有型別)
*/
```

### 讓參數接受null
```typescript
function calculateTax(amount: number | null, discount: number = 0, ...extraFees: number[]) {
	if (amount != null) {
	  return (amount * 1.2) - discount
	    + extraFees.reduce((total, val) => total + val, 0);
	}
}
let taxValue = calculateTax(null, 0); // taxValue = undefined
/*
可以接受null傳入
但最後會得到undefined (Implicit Return)
*/
```


### 自動推論傳回值的型別
```typescript=
// "declaration": true,    
declare function calculateTax(amount: number | null, discount?: number, ...extraFees: number[]): number | undefined;
declare let taxValue: number | undefined;
```

### 禁止隱性傳回值Implicit Return
```typescript
function calculateTax(amount: number | null, discount: number = 0, ...extraFees: number[]) {
	if (amount != null) {
	    return (amount * 1.2) - discount
			+ extraFees.reduce((total, val) => total + val, 0);
	}
	return undefined
}
let taxValue = calculateTax(null, 0); // taxValue = undefined
/*
沒有明確的return傳回值就會提出警告
"noImplicitReturns": true
*/
```


### 傳回值使用型別註記
```typescript
function calculateTax(amount: number, discount: number = 0, ...extraFees: number[]): number {
  return (amount * 1.2) - discount
	    + extraFees.reduce((total, val) => total + val, 0);
}
let taxValue = calculateTax(100, 0); // taxValue = 120
let taxValue = calculateTax(null, 0);
// Argument of type 'null' is not assignable to parameter of type 'number'.
```

### 定義void傳回值
```typescript
function calculateTax(amount: number, discount: number = 0, ...extraFees: number[]): number {
  return (amount * 1.2) - discount
	    + extraFees.reduce((total, val) => total + val, 0);
}
function writeValue(label: string, value: number): void {
	console.log(label + ': ' + value);
}
let taxValue = calculateTax(100, 0); // taxValue = 120
writeValue("Tax value", calculatetax(100, 0));
// writeValue() 不會產生傳回值 => void型別
// 用了return會提出警告
```

### 型別多載Type Overloading
```typescript
function calculateTax(amount: number): number;
function calculateTax(amount: null) null;
function calculateTax(amount: number | null): number | null {
    if (amount != null) {
        return amount * 1.2;
    }
    return null;
}
function writeValue(label: string, value: number): void {
	console.log(label + ': ' + value);
}

let taxValue: number = calculateTax(100); // taxValue = 120
// 接收number型別傳回值 可以直接使用
writeValue("Tax value", taxValue);
// => Tax value: 120

```

### *條件型別
```typescript=
type taxType<T extends boolean> = T extends true ? number : null
let taxValue: taxType<true> = calculateTax(100);
let taxValue: taxType<false> = calculateTax(null);
```