如果我有类型:
interface ITest {
a: number;
b: string;
}
我可能想定义一个函数,该函数通过该接口动态设置对象的属性。
我可以找到一些办法,但是以下代码似乎无法正确比较键和值类型:
interface ITest {
a: number;
b: string;
}
const item: ITest = {
a: 1,
b: 'A Test',
}
const setValue = <K extends keyof ITest>(x: ITest) =>
(key: K) =>
(value: ITest[K]) => x[key] = value;
参与其中。但是,通过将其放置在操场上,我们得到的结果并不明确:
interface ITest {
a: number;
b: string;
}
const item: ITest = {
a: 1,
b: 'A Test',
}
const setValue = <K extends keyof ITest>(x: ITest) =>
(key: K) =>
(value: ITest[K]) => x[key] = value;
setValue(item)('a')('test');
setValue(item)('b')(false); // only this ones shows an error
setValue(item)('b')(1);
setValue(item)('b')('b'); // if properly working, only this will work
这似乎意味着只要value
是ITest
上任何值的类型,编译器都会感到满意。
答案 0 :(得分:1)
定义可能应该是:
const setValue = (x: ITest) =>
<K extends keyof ITest>(key: K) =>
(value: ITest[K]) => x[key] = value;
您可以测试的
setValue(item)("a")(3); // okay
setValue(item)("b")("hello"); // okay
setValue(item)("c")(123); // error!
// ---------> ~~~
// "c" is not assignable to "a" | "b".
setValue(item)("a")("whoops"); // error!
// --------------> ~~~~~~~~
// "whoops" is not assignable to number
想法是setValue
本身是一个具体的非泛型函数,但是setValue(item)
返回的函数应该是K
的{{1}}类型的泛型,然后应将函数 返回的key
参数限制为value
。
请注意,您不希望ITest[K]
本身在setValue
中是通用的,否则当您调用K
时,将已经指定setValue(item)
的类型,然后返回的函数将是类型为K
的具体类型,它允许诸如(key: keyof ITest)=>(value: ITest[keyof ITest])=>ITest[keyof ITest]
这样的坏事情:
setValue(item)("a")("whoops")
此外,由于const badSetValue = <K extends keyof ITest>(x: ITest) =>
(key: K) =>
(value: ITest[K]) => x[key] = value;
badSetValue(item)("a")(3); // okay
badSetValue(item)("b")("hello"); // okay
badSetValue(item)("c")(123); // error!
// ------------> ~~~
// "c" is not assignable to "a" | "b".
badSetValue(item)("a")("whoops"); // okay?! uh oh
的实现是如此普遍,因此您可能决定您希望它变得更加普遍:
setValue()
与const generalSetValue = <T>(x: T) =>
<K extends keyof T>(key: K) =>
(value: T[K]) => x[key] = value;
对象上的setValue()
类似,
ITest
但在其他对象类型上也同样适用:
generalSetValue(item)("a")(3); // okay
generalSetValue(item)("b")("hello"); // okay
generalSetValue(item)("c")(123); // error!
// ----------------> ~~~
// "c" is not assignable to "a" | "b".
generalSetValue(item)("a")("whoops"); // error!
// ---------------------> ~~~~~~~~
// "whoops" is not assignable to number
好的,希望能有所帮助;祝你好运!