使用typescript推導已有變量的盲盒類型詳情
遷移盲盒
當我們從JavaScript一鍵轉換Typescript的時候,any便是最省事的做法,對于維護并不友好(雖然能跑就行),同時每個變量對于我們來說都是盲盒,它到底是什么類型?
類型推導
基礎類型的推導
基礎數據類型的類型推導還是挺簡單的
let a = 1; type A = typeof a; // number; let b = '2' type B = typeof b; // string; let c; type C = typeof c; // undefined;
一個typeof就可以把原始值類型推導出來了!
我們整理下基礎數據類型有哪些?
// 沒錯,7種數據類型 type Base = string | number | boolean | null | undefined | symbol | bigint;
對象的推導
這里我們來實現下普通對象如何推導
let obj = { a: 1, b: '2', c: true, d: null }; type Obj = typeof obj; // { a: number; b: string; c: boolean; d: null; }
沒錯,也是這么簡單!
數組的推導
為什么上面的對象除開數組呢?因為數組在typescript比較特殊,既可以用元祖來聲明,又可以用數組來聲明
也可以說數組包含了元祖
type isContain = [1, 2] extends Array<number> ? true : false; // true
嘗試繼續(xù)通過typeof來實現推導
let arr = [1, '2', null, false]; type Arr = typeof arr; // (string | number | boolean | null)[] ??? type Arr1 = typeof arr[0] // string | number | boolean | null ???
好吧,得到的竟然是聯合類型數組,是不是和我們預期的不一樣?
我們定義一個數組,卻沒有聲明類型,對于數組來說,默認就是 Array,由于不斷填充了 number,string,null,boolean的值,最后變成了 Array<string | number | boolean | null>,而且是每一個元素都是聯合類型
重新整理下,我們需要的是啥?
[1, '2', null, false]
-> [number, string, null, boolean]
我們要的是元祖 [number, string, null, boolean]
,而不是數組 Array<string | number | boolean | null>
整理下todo,我們需要的是:
- 固定長度的數組類型
- 每個元素都有獨立的類型
let arr = [1, '2', null, false] as const; type Arr = typeof arr; // readonly [1, '2', null, false] type Arr1 = typeof arr[0] // 1
第一個 todo 實現了,第二個有點像,但又不對,我們要的是數據類型,而不是某個具體的值
實現一個轉換類型的泛型
我們要的是 1 轉 number, 'A' 轉 string,只需要列出所有的基礎類型做轉換就可以了
type GetType<T> = T extends string ? string : T extends number ? number : T extends boolean? boolean : T extends null ? null : T extends undefined ? undefined : T extends symbol ? symbol : T extends bigint ? bigint : T; type Arr1 = typeof arr[0] // number type Arr2 = typeof arr[1] // string
那再遍歷一次元祖就可以實現整個數組的類型轉換了
type TransArr<T extends Array<unknown>, R extends unknown[] = []> = { 'loop': TransArr<T, [...R, T extends Base ? GetType<T[R['length']]>: T[R['length']] ] >, 'result': R, }[T['length'] extends R['length'] ? 'result': 'loop']; let arr = [1, '2', null, false] as const; type Arr = typeof arr; type ArrType = TransArr<Arr>; // [number, string, null, boolean]
函數的推導
函數的推導其實沒有必要,為什么這么說,函數參數和值類型不可控,除個別操作符或者明確類型
如 (a, b) => a * b ,返回值一定是number
如 (a) => Promise.resolve(a),返回值一定是Promise
let fn1 = (a, b) => a * b; type Fn1 = typeof fn1; // (a: any, b: any) => number function fn2(a) { return Promise.resolve(a); } type Fn2 = typeof fn2; // (a: any) => Promise<any>
大多是函數經過typeof后得到的結果是
(a: any, b: any, ...) => any;
這個類型可以限定參數數量更多的函數
function fn3(a, b, c) { return a + b + c; } function fn4(d) { return d + 1; } type Fn3 = typeof fn3; // (a: any, b: any, c: any) => any type Fn4 = typeof fn4; // (d: any) => any type F3_4 = Fn3 extends Fn4 ? true : false; // false type F4_3 = Fn4 extends Fn3 ? true : false; // true
也就是說,參數多的函數總是包含了參數少的函數
根據上面的判斷,我們可以通過這個來實現函數的判斷
type isFunc<T> = (() => any) extends T ? true : false;
完善推導
- 基礎類型直接返回類型
- 數組用TransArr泛型轉一次
- 函數直接返回typeof的值
- 遍歷對象則用keyof實現
type Trans<T> = T extends Base ? GetType<T> : T extends Array<unknown> ? TransArr<T> : isFunc<T> extends true ? T : { [key in keyof T]: T[key] extends Base ? GetType<T[key]> : T[key] extends Array<unknown> ? TransArr<T[key]> : Trans<T[key]>; };
測試
let a1 = 1; type test1 = Trans<typeof a1>; // number let a2 = '2'; type test2 = Trans<typeof a2>; // string let a3 = [1, '2', true, '3', 4] as const; type test3 = TransArr<typeof a3>; // [number, string, boolean, string, number] let a4 = { a: 1, b: true, c: { a: 1, b: [1, '2'] }, d: [true, null] } as const; type test4 = Trans<typeof a4>; // { // readonly a: number; // readonly b: boolean; // readonly c: { // readonly a: number; // readonly b: readonly [number, string]; // }; // readonly d: readonly [boolean, null]; // } let a5 = { a: [ { b: [ { c: 1 } ] } ] } as const; type test5 = Trans<typeof a5>; // { // readonly a: readonly [{ // readonly b: readonly [{ // readonly c: number; // }]; // }]; // } let a6 = (a, b, c) => a + b + c; type test6 = Trans<typeof a6>; // (a: any, b: any, c: any) => any let a7 = [ function fn() { return 1; }, (a, b) => a * b, (a) => Promise.resolve(a) ] as const; type test7 = TransArr<typeof a7>; // [() => number, (a: any, b: any) => number, (a: any) => Promise<any>] let a8 = { a: 1, b: [true, null], c: [() => void, (a, b) => a], d: { e: [ (a, b) => null, { f: [1] } ] } } as const; type test8 = Trans<typeof a8>; // { // readonly a: number; // readonly b: readonly [boolean, null]; // readonly c: readonly [() => undefined, (a: any, b: any) => any]; // readonly d: { // readonly e: readonly [(a: any, b: any) => null, { // readonly f: readonly [number]; // }]; // }; // }
到此這篇關于使用typescript推導已有變量的盲盒類型詳情的文章就介紹到這了,更多相關typescript盲盒類型內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!