Art*_*rev 3 typescript typescript-generics
当我交换对象键值时,函数的返回类型是 { [x: string]: value } instedof const key。
游乐场在这里
interface IObj {
[key: string]: string;
};
const swapFn = <T extends IObj>(obj: T) => {
const res = {} as { [K in T[keyof T]]: keyof T };
Object.entries(obj).forEach(([key, value]) => {
res[value as T[keyof T]] = key;
});
return res;
}
// return type should be:
// {
// aaa: 'a',
// bbb: 'b',
// } insted of {
// [x: string]: "a" | "b";
// }
const result = swapFn({
a: 'aaa',
b: 'bbb',
});
Run Code Online (Sandbox Code Playgroud)
这里有两个问题。首先是您的返回类型太宽,因为keyof T是所有键的并集;每个属性"a" | "b"都不是特定的"a"或"b"对应的值。这可以通过更改映射类型来解决,并且可以通过TypeScript 4.1 中引入的键重新映射来特别轻松地完成:
{ [K in keyof T as T[K]]: K }
Run Code Online (Sandbox Code Playgroud)
我们遍历 的每个键K,T并将输出T[K](属性值类型)作为键和K属性。这就交换了东西。
第二个问题是推理问题。当您传入时,{ a: 'aaa', b: 'bbb'}编译器很可能会推断该值具有类型{a: string, b: string},因为更常见的是,人们可能希望将属性的值更改为其他值,string而不是将其保留为某些字符串文字。有不同的方法可以说服编译器推断更窄的类型。最简单的是调用者使用const断言:
swapFn({ s: "t", u: "v" } as const);
Run Code Online (Sandbox Code Playgroud)
但如果您不希望呼叫者必须这样做,您可以使用其他技巧。请参阅microsoft/TypeScript#30680以获取功能请求,要求提供一些不太疯狂的技巧及其一些描述。我将添加另一个泛型类型参数,S extends string该参数除了向编译器提示您需要字符串文字类型外没有其他用途。相反T extends IObj,我会写T extends Record<string, S>。
这是完整的功能:
const swapFn = <T extends Record<string, S>, S extends string>(obj: T) => {
const res = {} as any; // I'm not worried about impl safety
Object.entries(obj).forEach(([key, value]) => {
res[value] = key;
});
return res as { [K in keyof T as T[K]]: K };
}
Run Code Online (Sandbox Code Playgroud)
我改变了类型断言;编译器并没有真正具备验证“交换键和值”实现的类型安全性的能力,因此我懒得尝试,并使用any.
让我们看看它是否有效:
const result = swapFn({
a: 'aaa',
b: 'bbb',
});
/* const result: {
aaa: "a";
bbb: "b";
} */
console.log(result.aaa.toUpperCase()) // A
Run Code Online (Sandbox Code Playgroud)
看起来不错!
| 归档时间: |
|
| 查看次数: |
2290 次 |
| 最近记录: |