有熟悉 typescript 的前端大佬吗, 问一个关于类型推断的问题 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐关注
Meteor
JSLint - a Javascript code quality tool
jsFiddle
D3.js
WebStorm
推荐书目
Javascript 权威指南第 5 版
Closure: The Definitive Guide
kkopitehong
V2EX    Javascript

有熟悉 typescript 的前端大佬吗, 问一个关于类型推断的问题

  •  1
     
  •   kkopitehong 2019-12-05 10:58:00 +08:00 4160 次点击
    这是一个创建于 2165 天前的主题,其中的信息可能已经有所发展或是发生改变。
    interface Foo { name: string type: string } function transform(arr: Foo[]) { const obj = {} arr.forEach(item => { obj[item.name] = { ... } }) return obj } transform([ { name: 'tom', type: 'confirm' }, { name: 'jack', type: 'confirm' } ]) // { tom: {}, jack: {} } 

    transform方法将传入的数组中每一个对象的name属性值作为 key, 返回一个对象, 这个要怎么写类型声明, 让返回的对象能推断出其有tomjack这两个属性

    之前用到inquirer, 就有这种推断, 但是看其声明文件看的云里雾里的,照着写好像也不大对

    Q3wH4x.md.gif

    gif 地址 (编辑时预览的 gif 貌似没有动, 直接传图片)

    13 条回复    2019-12-05 13:39:50 +08:00
    BBCCBB
        1
    BBCCBB  
       2019-12-05 11:05:53 +08:00
    看过 typescript, 但没怎么写过, 我瞎说一下 ==.

    interface A {
    tom: any
    jack: any
    }


    function xxx(): A {}
    BBCCBB
        2
    BBCCBB  
       2019-12-05 11:06:52 +08:00
    但这样写 transform 方法目测又要报错了
    kkopitehong
        3
    kkopitehong  
    OP
       2019-12-05 11:09:32 +08:00
    @BBCCBB 不能直接这样声明返回类型嗯 因为传入的每一个对象的`name`属性值都是不确定的
    hyyou2010
        4
    hyyou2010  
       2019-12-05 11:32:24 +08:00
    好久没看了,水平也有限,猜是类似这样的东西:

    interface A {
    [key:string]: any
    [propName:string]: any
    [index:string|number]:any
    }
    hyyou2010
        5
    hyyou2010  
       2019-12-05 11:35:09 +08:00
    另外,如果只有 tom 和 jack 这两种可能的话,应该用枚举。同时函数的输入参数也应该用枚举限制为只有 tom 和 jack
    kkopitehong
        6
    kkopitehong  
    OP
       2019-12-05 11:45:25 +08:00
    @hyyou2010 这个是不定的, 比方我传入[{name: 'foo'}, {name: 'bar'}], 那返回的就应该是{ foo: {}, bar: {} }
    kkopitehong
        7
    kkopitehong  
    OP
       2019-12-05 11:48:10 +08:00
    @hyyou2010 你可以装下 inquirer 看看效果, 尝试修改下传入对象的 name
    yuanfnadi
        8
    yuanfnadi  
       2019-12-05 11:51:39 +08:00
    ```
    interface PathArray<T, L> extends Array<string | number> {
    ["0"]?: keyof T;
    ["1"]?: L extends {
    ["0"]: infer K0;
    }
    ? K0 extends keyof T
    ? keyof T[K0]
    : never
    : never;
    ["2"]?: L extends {
    ["0"]: infer K0;
    ["1"]: infer K1;
    }
    ? K0 extends keyof T
    ? K1 extends keyof T[K0]
    ? keyof T[K0][K1]
    : never
    : never
    : never;
    ["3"]?: L extends {
    ["0"]: infer K0;
    ["1"]: infer K1;
    ["2"]: infer K2;
    }
    ? K0 extends keyof T
    ? K1 extends keyof T[K0]
    ? K2 extends keyof T[K0][K1]
    ? keyof T[K0][K1][K2]
    : never
    : never
    : never
    : never;
    ["4"]?: L extends {
    ["0"]: infer K0;
    ["1"]: infer K1;
    ["2"]: infer K2;
    ["3"]: infer K3;
    }
    ? K0 extends keyof T
    ? K1 extends keyof T[K0]
    ? K2 extends keyof T[K0][K1]
    ? K3 extends keyof T[K0][K1][K2]
    ? keyof T[K0][K1][K2][K3]
    : never
    : never
    : never
    : never
    : never;
    ["5"]?: L extends {
    ["0"]: infer K0;
    ["1"]: infer K1;
    ["2"]: infer K2;
    ["3"]: infer K3;
    ["4"]: infer K4;
    }
    ? K0 extends keyof T
    ? K1 extends keyof T[K0]
    ? K2 extends keyof T[K0][K1]
    ? K3 extends keyof T[K0][K1][K2]
    ? K4 extends keyof T[K0][K1][K2][K3]
    ? keyof T[K0][K1][K2][K3][K4]
    : never
    : never
    : never
    : never
    : never
    : never;
    ["6"]?: L extends {
    ["0"]: infer K0;
    ["1"]: infer K1;
    ["2"]: infer K2;
    ["3"]: infer K3;
    ["4"]: infer K4;
    ["5"]: infer K5;
    }
    ? K0 extends keyof T
    ? K1 extends keyof T[K0]
    ? K2 extends keyof T[K0][K1]
    ? K3 extends keyof T[K0][K1][K2]
    ? K4 extends keyof T[K0][K1][K2][K3]
    ? K5 extends keyof T[K0][K1][K2][K3][K4]
    ? keyof T[K0][K1][K2][K3][K4][K5]
    : never
    : never
    : never
    : never
    : never
    : never
    : never;
    }

    type ArrayHasIndex<MinLenght extends number> = { [K in MinLenght]: any };

    export type PathArrayValue<
    T,
    L extends PathArray<T, L>
    > = L extends ArrayHasIndex<0 | 1 | 2 | 3 | 4 | 5 | 6 | 7>
    ? any
    : L extends ArrayHasIndex<0 | 1 | 2 | 3 | 4 | 5 | 6>
    ? T[L[0]][L[1]][L[2]][L[3]][L[4]][L[5]][L[6]]
    : L extends ArrayHasIndex<0 | 1 | 2 | 3 | 4 | 5>
    ? T[L[0]][L[1]][L[2]][L[3]][L[4]][L[5]]
    : L extends ArrayHasIndex<0 | 1 | 2 | 3 | 4>
    ? T[L[0]][L[1]][L[2]][L[3]][L[4]]
    : L extends ArrayHasIndex<0 | 1 | 2 | 3>
    ? T[L[0]][L[1]][L[2]][L[3]]
    : L extends ArrayHasIndex<0 | 1 | 2>
    ? T[L[0]][L[1]][L[2]]
    : L extends ArrayHasIndex<0 | 1>
    ? T[L[0]][L[1]]
    : L extends ArrayHasIndex<0>
    ? T[L[0]]
    : never;

    export type Path<T, L> = PathArray<T, L> | keyof T;

    export type PathValue<T, L extends Path<T, L>> = L extends PathArray<T, L>
    ? PathArrayValue<T, L>
    : L extends keyof T
    ? T[L]
    : any;

    declare function path<T, L extends Path<T, L>>(
    object: T,
    params: L
    ): PathValue<T, L>;

    const obj = {
    v: {
    w: { x: { y: { z: { a: { b: { c: 2 } } } } } },
    ouch: true,
    foo: [{ bar: 2 }, { bar: 3 }]
    }
    };

    const output: number = path(obj, ["v", "w", "x"]); //
    const output2: object = path(obj, ["v", "w", "x"]); //
    const output4: { c: string } = path(obj, ["v", "w", "x", "y", "z", "a", "b"]); //
    const output3: { c: number } = path(obj, ["v", "w", "x", "y", "z", "a", "b"]); //
    const output5: "wrong" = path(obj, ["v", "w", "x", "y", "z", "a", "b", "c"]); // since after 7 levels there is no typechecking

    const x = path(obj, ["v", "ouch", "x"]); //
    const y = path(obj, ["v", "ouch", "y"]); //
    const z = path(obj, ["v", "ouch", "somethingCompletelyDifferent"]); //

    path(obj, "!"); //
    path(obj, ["!"]); //
    path(obj, ["v", "!"]); //
    path(obj, ["v", "w", "!"]); //
    path(obj, ["v", "w", "x", "!"]); //
    path(obj, ["v", "w", "x", "y", "!"]); //
    path(obj, ["v", "w", "x", "y", "z", "!"]); //
    path(obj, ["v", "w", "x", "y", "z", "a", "!"]); //
    path(obj, ["v", "w", "x", "y", "z", "a", "b", "!"]); // since after 7 levels there is no typechecking
    path(obj, "v"); //
    path(obj, ["v"]); //
    path(obj, ["v", "w"]); //
    path(obj, ["v", "w", "x"]); //
    path(obj, ["v", "w", "x", "y"]); //
    path(obj, ["v", "w", "x", "y", "z"]); //
    path(obj, ["v", "w", "x", "y", "z", "a"]); //
    path(obj, ["v", "w", "x", "y", "z", "a", "b"]); //
    path(obj, ["v", "w", "x", "y", "z", "a", "b", "c"]); //
    ```
    likoshow
        9
    likoshow  
       2019-12-05 12:41:55 +08:00   3
    type ReturnObj<T extends string> = {
    [key in T]: any;
    };

    interface Foo {
    name: string;
    type: string;
    }

    function transform<T extends Foo['name']>(arr: {
    name: T,
    type: string
    }[]) {
    const obj = {} as ReturnObj<T>
    arr.forEach(item => {
    obj[item.name] = {
    // ...
    };
    });
    return obj as ReturnObj<T>
    }

    const result = transform([
    { name: "tom", type: "confirm" },
    { name: "jack", type: "confirm" }
    ]);
    keelii
        10
    keelii  
       2019-12-05 13:16:59 +08:00
    tom 和 jack 这两个属性不是类型,是运行时的字符串变量。你想把它推断出来只能手动写上 String Literal Type
    miaowing
        11
    miaowing  
       2019-12-05 13:29:06 +08:00
    @hyyou2010 同感觉是这个
    kkopitehong
        12
    kkopitehong  
    OP
       2019-12-05 13:35:44 +08:00
    @likoshow 感谢
    kkopitehong
        13
    kkopitehong  
    OP
       2019-12-05 13:39:50 +08:00   1
    @likoshow 稍做下修改

    ```
    type ReturnObj<T extends string> = {
    [key in T]: any;
    };

    interface Foo<T extends string> {
    name: T;
    type: string;
    }

    function transform<T extends string>(arr: Foo<T>[]) {
    const obj = {} as ReturnObj<T>
    arr.forEach(item => {
    obj[item.name] = {
    // ...
    };
    });
    return obj as ReturnObj<T>
    }
    ```
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2376 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 25ms UTC 01:57 PVG 09:57 LAX 17:57 JFK 20:57
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86