【问题标题】:Can I turn two types <K, V> into an object type with a single field with those types?我可以将两种类型 <K, V> 转换为具有这些类型的单个字段的对象类型吗?
【发布时间】:2021-05-05 12:59:44
【问题描述】:

我有一个函数:

const singleton = <K extends string, V>(k: K, v: V) => ({[k]: v})

this 的推断返回类型是{ [x: string]: V; },这意味着我做不到:

const foo: {bar: 'baz'} = singleton('bar', 'baz');

是否可以在 TypeScript 中为这个函数提供更好的返回类型,以便第二个 sn-p 类型检查?

(我显然只希望函数的第一个参数是文字字符串时才有效。)

我尝试了以下方法:

<K extends string, V>(k: K, v: V): {[K]: V} => ({[k]: v})

但它说:

类型文字中的计算属性名称必须引用其类型为文字类型或“唯一符号”类型的表达式。(1170)

'K' 仅指一种类型,但在这里用作值。(2693)

Playground

【问题讨论】:

    标签: typescript


    【解决方案1】:

    这不是类型安全的有充分的理由。虽然T extends string 将确保Tstring 的子类型,但认为T 必须是字符串文字类型是错误的。它也可以是字符串文字类型的联合:

    const singleton = <K extends string, V>(k: K, v: V) => ({[k]: v})
    
    const key = Math.random() > 0.5 ? "baz": "bar";
    const foo: { bar: number, baz: number } = singleton(key, 0) as Record<typeof key, number>;
    
    // one of these, at random will fail at runtime 
    foo.bar.toExponential
    foo.baz.toExponential
    

    Playground Link

    现在打字稿可以在这里做得更好吗?可以说它可以推断出Partial&lt;Record&lt;K, V&gt;&gt;。还有一个关于这个主题的问题,我目前找不到。

    要获得你想要的类型,你需要在函数体中使用类型断言。您可以向Record&lt;K, V&gt; 断言(需要注意的是,如果K 是一个联合,这是不安全的)或者您可以向Partial&lt;Record&lt;K, V&gt;&gt; 断言,这样更安全但不太方便。

    const singleton = <K extends string, V>(k: K, v: V) => ({[k]: v})as Partial<Record<K, V>>;
    
    const key = Math.random() > 0.5 ? "baz": "bar";
    const foo = singleton(key, 0) 
    
    foo.bar?.toExponential
    foo.baz?.toExponential
    
    

    Playground Link

    如果你想发挥创意,你可以测试一下T 是否是一个联合体。使用类似this

    type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never
    const singleton = <K extends string, V>(k: K, v: V) => ({[k]: v})as ( [K] extends [UnionToIntersection<K>] ? Record<K, V>: Partial<Record<K, V>>);
    
    const key = Math.random() > 0.5 ? "baz": "bar";
    const foo = singleton(key, 0) 
    
    foo.bar?.toExponential
    foo.baz?.toExponential
    
    
    const foo2 = singleton("key", 0) 
    foo2.key
    
    

    Playground Link

    【讨论】:

    • 谢谢,您对默认推断的类型的解释是有道理的。所以没有办法更具体地说一个类型应该是一个文字字符串?我稍微修改了你的最后一个 sn-p 以获得更好的推断类型,而且我不想支持 key 作为联合类型。你认为它仍然是类型安全的吗?
    猜你喜欢
    • 1970-01-01
    • 2020-01-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-09
    • 2016-05-05
    • 2015-03-04
    相关资源
    最近更新 更多