const 斷言 & infer 關鍵字


Posted by TempuraEngineer on 2023-11-17

目錄


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


#TypeScript #const assertion #infer keyword #conditional type







Related Posts

串接 Firebase SDK 做 Google OAuth 第三方登入

串接 Firebase SDK 做 Google OAuth 第三方登入

瀏覽網頁extension- Wappalyzer

瀏覽網頁extension- Wappalyzer

安裝 Spring Boot - spring boot initializr

安裝 Spring Boot - spring boot initializr


Comments