And*_*kin 8 types typescript mapped-types
我怎样才能把类型{ 'k': number, [s: string]: any }和抽象放在'k'和 上number?我想要一个类型别名T,以便T<'k', number>给出所述类型。
考虑以下示例:
function f(x: { 'k': number, [s: string]: any }) {} // ok
type T_no_params = { 'k': number, [s: string]: any }; // ok
type T_key_only<k extends string> = { [a in k]: number }; // ok
type T_value_only<V> = { 'k': V, [s: string]: any}; // ok
type T_key_and_index<k extends string, V> = { [a in k]: V, [s: string]: any };// ?
Run Code Online (Sandbox Code Playgroud)
{ 'k': number, [s: string]: any}直接使用作为函数参数的类型f有效。[s: string]: any索引部分type有效k extends stringin type-alias 也有效k extends string与[s: string]: anyin same type-alias结合使用时,我得到一个解析错误(甚至不是语义错误,它甚至似乎不是有效的语法)。这在这里似乎有效:
type HasKeyValue<K extends string, V> = { [s: string]: any } & { [S in K]: V }
Run Code Online (Sandbox Code Playgroud)
但是在这里,我不太明白为什么它不抱怨额外的属性(右侧的类型&不应允许具有额外属性的对象)。
编辑:
答案中多次提到&是交集算子,它的行为应该类似于集合论交集。然而,当涉及到额外属性的处理时,情况并非如此,如以下示例所示:
function f(x: {a: number}){};
function g(y: {b: number}){};
function h(z: {a: number} & {b: number}){};
f({a: 42, b: 58}); // does not compile. {a: 42, b: 58} is not of type {a: number}
g({a: 42, b: 58}); // does not compile. {a: 42, b: 58} is not of type {b: number}
h({a: 42, b: 58}); // compiles!
Run Code Online (Sandbox Code Playgroud)
在这个例子中,似乎{a: 42, b: 58}既不是 type {a: number},也不是 type {b: number},但它以某种方式结束了交集{a: number} & {b: number}。这不是集合论交集的工作原理。
这正是我自己的&建议看起来如此可疑的原因。如果有人能详细说明如何将映射类型与“相交”{ [s: string]: any }可以使类型“更大”而不是使其更小,我将不胜感激。
我看过问题
但这些似乎没有直接关系,尽管名称相似。
type HasKeyValue<K extends string, V> = { [s: string]: any } & { [S in K]: V }是定义您所追求的类型的正确方法。但需要知道的一件事是(释义已弃用的标志:keyofStringsOnly):
\n\nkeyof 类型运算符返回字符串 | 当应用于具有字符串索引签名的类型时,数字而不是字符串。
\n
我不知道有什么方法可以将索引限制为类型string而不是string | number。实际上允许number访问string索引似乎是一件合理的事情,因为它符合 Javascript 的工作方式(人们总是可以将数字字符串化)。另一方面,您无法安全地访问带有字符串值的数字索引。
类型&运算符的工作原理与集合理论交集类似 - 它始终限制可能值的集合(或使它们保持不变,但从不扩展)。在您的情况下,该类型排除任何非类似字符串的键作为索引。准确地说,您将其排除unique symbol为索引。
我认为您的困惑可能来自于 Typescript 处理函数参数的方式。使用显式定义的参数调用函数的行为与将参数作为变量传递不同。在这两种情况下,Typescript 确保所有参数都具有正确的结构/形状,但在后一种情况下,它还不允许额外的 props。
\ntype HasKeyValue<K extends string, V> = { [s: string]: any } & { [S in K]: V };\ntype WithNumber = HasKeyValue<"n", number>;\nconst x: WithNumber = {\n n: 1\n};\n\ntype T = keyof typeof x; // string | number\nx[0] = 2; // ok - number is a string-like index\nconst s = Symbol("s");\nx[s] = "2"; // error: cannot access via symbol\n\ninterface N {\n n: number;\n}\n\nfunction fn(p: N) {\n return p.n;\n}\n\nconst p1 = {\n n: 1\n};\n\nconst p2 = {\n n: 2,\n s: "2"\n};\n\nfn(p1); // ok - exact match\nfn(p2); // ok - structural matching: { n: number } present; additional props ignored\nfn({ n: 0, s: "s" }); // error: additional props not ignore when called explictily\nfn({}); // error: n is missing\nRun Code Online (Sandbox Code Playgroud)\n对象字面量 - 显式创建某种形状的对象,例如const p: { a: number} = { a: 42 }Typescript 以特殊方式处理的对象。与常规结构推理相反,类型必须完全匹配。说实话,这是有道理的,因为这些额外的属性 - 没有额外的可能不安全的演员 - 无论如何都是无法访问的。
\n\n\n[...] 然而,TypeScript 的立场是这段代码中可能存在\xe2\x80\x99s 错误。对象字面量在将它们分配给其他变量或将它们作为参数传递时会受到特殊处理并进行过多的属性检查。如果对象字面量具有 \xe2\x80\x9c 目标类型\xe2\x80\x9d 不具有的任何属性,\xe2\x80\x99 将收到错误。[...] 绕过这些检查的最后一种方法(可能有点令人惊讶)是将对象分配给另一个变量。
\n
解决此错误的另一个选项是...将其与 相交{ [prop: string]: any }。
function f(x: { a: number }) {}\nfunction g(y: { b: number }) {}\nfunction h(z: { a: number } & { b: number }) {}\n\nf({ a: 42, b: 58 } as { a: number }); // compiles - cast possible, but `b` inaccessible anyway\ng({ a: 42 } as { b: number }); // does not compile - incorrect cast; Conversion of type \'{ a: number; }\' to type \'{ b: number; }\' may be a mistake\nh({ a: 42, b: 58 }); // compiles!\n\nconst p = {\n a: 42,\n b: 58\n};\n\nf(p); // compiles - regular structural typing\ng(p); // compiles - regular structural typing\nh(p); // compiles - regular structural typing\n\nconst i: { a: number } = { a: 42, b: 58 }; // error: not exact match\nf(i); // compiles\ng(i); // error\nh(i); // error\nRun Code Online (Sandbox Code Playgroud)\n
| 归档时间: |
|
| 查看次数: |
481 次 |
| 最近记录: |