interface Itest {
a: { a: number };
b: { b: number };
c: { c: number };
d: { d: number };
}
type Tname = keyof Itest;
interface Isdk {
init: (
dep: Tname[],
param: (<T extends Tname, K = Itest[T]>(name: T) => K | undefined) | Itest[Tname]
) => void;
}
const SDK: Isdk = {
init: (dep, param) => {},
};
SDK.init(['a'], (name) => {
if (name === 'a') {
return {
a: 1,
};
}
if (name === 'b') {
return {
a: 1,
};
}
if (name === 'c') {
return {
a: 1,
};
}
if (name === 'd') {
return {
a: 1,
};
}
return;
});
我想根据输入定义返回接口,例如,如果名称是a,那么返回值必须是{ a: number }
。
1条答案
按热度按时间lf5gs5x21#
您的代码的问题是,当您通过
if (name === "a") {return {a: 1}}
检查generic类型K
的值name
时,此narrows的类型为name
,* 但当前它不会缩小或重新约束类型K
本身 *。你应该返回indexed access类型的值
Test[K]
,但是当你返回return {a: 1}
时,编译器无法验证这是否合适。如果K
可以被限制为"a"
,那么Test[K]
可以被计算为Test["a"]
,即{a: number}
。然后{a: 1}
将被接受。但这并没有发生,所以你会得到一个编译器错误。对于所有其他检查
if (name === "b")
等,也是如此。这是TypeScript的一个局限性,GitHub中有很多开放的功能要求在这里进行一些改进。如果microsoft/TypeScript#33014和/或microsoft/TypeScript#27808被实现,它可能会让你的代码按原样编译。
但在TypeScript 4.9中,它不是语言的一部分。
现在,如果您希望以编译器可以验证为安全的方式返回
Test[K]
这样的泛型索引访问类型的值,最好的方法是 * 实际执行一个索引操作 *,如return test[name]
,其中test
的类型为Test
,name
的类型为K
。你的函数中已经有
name
了,让我们重构一下,这样我们也可以提供test
:变量
test
是Test
类型的对象。每个属性都实现为a getter method,因此在运行时只计算您实际关心的属性。这会成功编译,因为
test[name]
已知为Test[K]
类型。Playground代码链接