APu*_*APu 2 javascript types typescript
如何在打字稿中输入以下函数,以便获得自动完成和错误预防功能。
使用打字稿 4.7.4
// reference fn
function doSomething(list) {
const data = {};
list.map(item => {
data[item] = 'value type string|number|bool|null'
});
return data;
}
// calling it like
const data = doSomething([
'phone_number',
'customer_email'
]);
// get IDE autocomplete here (for only properties inside data)
console.log(data.phone_number);
console.log(data.customer_email);
// typescript yell when try to access invalid properties
console.log(data.phone_numbersss);
Run Code Online (Sandbox Code Playgroud)
只要所使用的数组在函数调用时实际上是一个编译时常量(因此 TypeScript 知道它的值是什么),您就可以做到这一点。否则,TypeScript 不知道数组内容是什么,并且必须采用任何字符串。至少有两种方式可以满足约束:
\n您可以通过对其应用常量断言来直接说数组是常量:
\nconst names = ["phone_number", "customer_email"] as const;\n// \xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92^^^^^^^^\n
Run Code Online (Sandbox Code Playgroud)\n您可以在调用时使用数组文字,并使用可变元组类型作为参数的类型(更多内容见下文)。
\n一旦我们知道数组的内容是 TypeScript 的编译时常量,我们就可以使用映射类型来映射一个数组,该数组扩展string[]
为一个对象,并以数组元素作为键和所需的属性类型:
type DoSomethingResult<T extends readonly string[]> = {\n [Key in T[number]]: string | number | boolean | null;\n};\n
Run Code Online (Sandbox Code Playgroud)\n实现该函数需要创建对象(而不是数组)并为属性赋予一些值;我选择了null
:
function doSomething<T extends readonly string[]>(list: [...T]): DoSomethingResult<T> {\n // Variadic tuple type \xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92^^^^^^\n return Object.fromEntries(list.map((key) => [key, null])) as DoSomethingResult<T>;\n}\n
Run Code Online (Sandbox Code Playgroud)\n这是电话:
\nconst data = doSomething([\n "phone_number",\n "customer_email"\n]);\n
Run Code Online (Sandbox Code Playgroud)\n然后所有给定的测试用例都可以工作。
\n\n请注意,数组必须是数组文字;这行不通:
\n// WON\'T WORK AS DESIRED\nconst names = [\n "phone_number",\n "customer_email"\n];\nconst data = doSomething(names);\n
Run Code Online (Sandbox Code Playgroud)\nTypeScript 将数组的类型推断为string[]
,而不是["phone_number", "customer_email"]
。as const
(如果你在数组上添加一个,它就会起作用。)
如果您必须支持没有可变参数元组类型(在 v4.0 中引入)的 TypeScript 版本,您可以使用as const
以下版本:
function doSomething<T extends readonly string[]>(list: T): DoSomethingResult<T> {\n // Using `T` directly as the type \xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92^\n return Object.fromEntries(list.map((key) => [key, null])) as DoSomethingResult<T>;\n}\n// ...\nconst data = doSomething([\n "phone_number",\n "customer_email"\n] as const);\n//^^^^^^^^\n
Run Code Online (Sandbox Code Playgroud)\n\n