Typescript 我可以转两种类型吗<;K、 V>;是否转换为具有单个字段的对象类型?

Typescript 我可以转两种类型吗<;K、 V>;是否转换为具有单个字段的对象类型?,typescript,Typescript,我有一个功能: const singleton = <K extends string, V>(k: K, v: V) => ({[k]: v}) 是否可以在TypeScript中为该函数提供更好的返回类型,以便第二个代码段进行类型检查 (很明显,只有当函数的第一个参数是文本字符串时,我才希望这样做有效。) 我尝试了以下方法: <K extends string, V>(k: K, v: V): {[K]: V} => ({[k]: v}) (k:k,v:

我有一个功能:

const singleton = <K extends string, V>(k: K, v: V) => ({[k]: v})
是否可以在TypeScript中为该函数提供更好的返回类型,以便第二个代码段进行类型检查

(很明显,只有当函数的第一个参数是文本字符串时,我才希望这样做有效。)

我尝试了以下方法:

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

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

“K”仅指类型,但在此处用作值。(2693)


这不是类型安全的,有充分的理由。虽然
T extends string
将确保
T
string
的子类型,但认为
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

如果你想变得有创意,你可以测试一下
T
是否是一个联盟。使用类似

type UnionToIntersection=(U扩展任何?(k:U)=>void:never)扩展((k:inferi)=>void)?I:从来没有
const singleton=(k:k,v:v)=>({[k]:v})as([k]扩展[UnionToIntersection]?记录:部分);
const key=Math.random()>0.5?“baz”:“bar”;
常量foo=singleton(键,0)
foo.bar?.toExponential
foo.baz?.toExponential
const foo2=单态(“键”,0)
foo2.key

谢谢,您对默认推断类型的解释是有意义的。所以没有办法更具体地说,类型应该是文本字符串?我稍微修改了您的上一个代码片段,以获得更好的推断类型,而且我不想支持键是联合类型。你认为它还是打字安全的吗?
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
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

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