Typescript“Pick”意外允许任何属性值

Typescript“Pick”意外允许任何属性值,typescript,Typescript,下面是一个使用TS4.1.3编译的简单类型I: interface Foo { [key: string]: any; bar: 'baz'; } 这应该允许对任何属性使用任何值,除了条,它仅限于一个值。例如,我不能执行const x:Foo={bar:'asdfadsf'}。这正是我所期望的 然后我会这样做: type Bar = Pick<Foo, string>; 类型栏=拾取; 除非我误解了Pick的工作原理,否则这应该是不可操作的,因为所有键都在str

下面是一个使用TS4.1.3编译的简单类型I:

interface Foo {
    [key: string]: any;
    bar: 'baz';
}
这应该允许对任何属性使用任何值,除了
,它仅限于一个值。例如,我不能执行
const x:Foo={bar:'asdfadsf'}
。这正是我所期望的

然后我会这样做:

type Bar = Pick<Foo, string>;
类型栏=拾取;
除非我误解了
Pick
的工作原理,否则这应该是不可操作的,因为所有键都在
string
中,包括
bar

然而,令我惊讶的是
const x:Bar={Bar:'asdfadsf'}
确实编译了

仅当我将
Bar
的定义更改为
Pick时它是否成为真正的禁止操作

我哪里做错了


旁白:显然这是一个MWE,实际场景涉及React和其他第三方库,最终我可以强制执行正确的类型签名,我只想学习。

为了理解这一点,您必须查看
拾取的定义以及它一步一步地做什么

这是typescript在幕后应用的类型:

type Pick<T, K extends keyof T> = { 
  [P in K]: T[P]; 
}
Foo[string]
any
,即使
Foo['bar']
baz
。 这里只有一个签名,因此它被简化为基本的字符串索引签名:

type Bar = {
  [x: string]: any;
}
当您将其更改为
Pick
时,它与
Pick
相同。这不再与字符串索引签名匹配,因此您得到的类型仅包括定义的键
bar

type Bar = {
    bar: 'baz';
}
也许最真实的禁止操作是分别选择两个签名并将它们组合起来:

type Bar = Pick<Foo, 'bar'> & Pick<Foo, string>;

我想我明白了,谢谢。
type Bar = {
    bar: 'baz';
}
type Bar = Pick<Foo, 'bar'> & Pick<Foo, string>;
type Bar = {
    bar: 'baz';
} & {
    [x: string]: any;
}