目錄
const斷言是什麼
const斷言(assertion)是一種型別斷言,它可以告訴Typescript限縮變數的型別、把變數變成readonly,寫immutable
code時會用到
它和const宣告的差別在於並不是用於宣告變數,而是限縮型別
,所以兩者使用的場景並不一樣
// 型別是string;
let fruit = 'apple';
// 型別是apple;
let fruit2 = 'apple' as const;
const fruit3 = 'apple';
let arr = [10, 20];
const arr2 = [10, 20] as const;
const arr3 = [10, 20];
arr.push(30);
arr2.push(30); // Property 'push' does not exist on type 'readonly [10, 20]'
arr3.push(30);
在一些需要enum的場景也可以使用const斷言代替
const mainDishes = {
beef:'steak',
pork:'pepper pork',
lamb:'roasted lamb',
fish:'sashimi',
shrimp:'curry shirmp',
carb:'butter crab',
} as const;
mainDishes.beef = 'roasted beef'; // Cannot assign to 'beef' because it is a read-only property.
const斷言限制
1.只能用於直接賦值宣告、簡單的表達式
```js
// bad
// A 'const' assertion can only be applied to a to a string, number, boolean, array, or object literal.
const num = 1 + 2 as const;
const day = new Date('2023-11-13') as const;
// ok
const num = 1 as const;
const set = new Set([1,2,3]);
const maxNum = Math.max(...[10,20,30]);
```
2.如果物件的屬性有reference
,那const斷言不
會對那個屬性生效
```js
let arr = ['chocolate'];
let person = {
name: "Derek",
favorite: arr,
hobby: ['gardening'],
} as const;
person.favorite.push('strawberry');
person.hobby.push('swimming'); // Property 'push' does not exist on type 'readonly ["gardening"]'.
```
infer關鍵字是什麼
infer關鍵字(keyword)可以在限縮型別的同時讓型別變得更彈性
用於條件型別(conditional type),能解決深度巢狀的條件型別
(a? b : c? d : e? f : g)
enum Desserts {
Cake = 'chocolate cake',
Jelly = 'organge jelly',
IceCream = 'macha ice cream'
}
// 攤平陣列取得element的型別
type Flatten<Type> = Type extends Array<infer Item> ? Item : Type;
type Sweets = Flatten<Desserts[]>; // 型別為Desserts
用於推斷return value型別、parameter型別
type GetReturnType<Type> = Type extends (...args: never[]) => infer Return ? Return : never;
type Num = GetReturnType<() => number>;
// 相當於
type Num2 = ReturnType<() => number>;
type GetParameterType<Type> = Type extends (arg: infer Args) => any ? Args : Type;
type Args = GetParameterType<(a:number, b: string) => void>
// 相當於
type Params = Parameters<(a:number, b: string) => void>;
React也提供了util type,只要傳component
給它就可以取得其props型別
type ComponentProps<
T extends keyof JSX.IntrinsicElements | JSXElementConstructor<any>
> = T extends JSXElementConstructor<infer P> ? P :
T extends keyof JSX.IntrinsicElements ? JSX.IntrinsicElements[T] : {};
type MyButtonProps = ComponentProps<typeof MyButton>;
type MyDivProps = ComponentProps<"div"> & {
customProperty: string;
};
infer關鍵字限制
不是conditional type時
,infer不能寫在
extend後(型別參數的限制子句
)
// bad
// 'infer' declarations are only permitted in the 'extends' clause of a conditional type.
type Item<T extends (infer U)[]> = U;
參考資料
TS - const assertions
TS - Inferring Within Conditional Types