如果键是字符串类型,为什么“key in myObject”不会缩小类型?

use*_*052 5 narrowing typescript

我不明白这一点:

const VALUES = {
  name: "name",
  age: "age",
  address: "address",
};

export function getVal(key: string) {
  if (key in VALUES) {
// Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{ name: string; age: string; address: string; }'.
//  No index signature with a parameter of type 'string' was found on type '{ name: string; age: string; address: string; }'.ts(7053)
    return VALUES[key];
  }

  return "";
}
Run Code Online (Sandbox Code Playgroud)

条件明确地使成为true 分支中的key键之一。VALUES那么为什么 typescript 会抱怨呢?不会key in obj缩小key成为 中的键之一吗obj

我知道我可以采取以下两种方法之一来修复它:

A/

const VALUES: { [index: string]: string } = {
  name: "name",
  age: "age",
  address: "address",
};
Run Code Online (Sandbox Code Playgroud)

乙/

export function getVal(key: keyof typeof VALUES) {
  ...
}
Run Code Online (Sandbox Code Playgroud)

但是,如果我想将VALUES类型限制为这些键,和/或key参数保留为 a ,该怎么办string

编辑:

正如 TJ Crowder 在评论中指出的那样,也许更好的“解决方案”是:

const VALUES = {
  name: "name",
  age: "age",
  address: "address",
};

function isValidKey(key: string): key is keyof typeof VALUES {
  return key in VALUES;
}

export function getVal(key: string) {
  if (isValidKey(key)) {
    return VALUES[key];
  }

  return "";
}
Run Code Online (Sandbox Code Playgroud)

jca*_*alz 5

TypeScript 支持通过in运算符缩小范围,但目前,类似的检查key in obj只能缩小 的类型obj,而不能缩小 的类型keyobj传统上,这仅在属于联合类型 时才有效,然后"k" in obj将联合过滤为仅具有已知k键的那些成员。TypeScript 4.9添加了对非联合类型的额外缩小in;因此,如果obj不是联合,"k" in obj将缩小为是属性的obj类型。这些缩小范围都对支票没有任何作用。obj.xunknownkeykey in obj

这种情况尚未发生的原因是它从未实施过。microsoft/TypeScript#43284有一个开放的功能请求,要求缩小key. 它被标记为“等待更多反馈”,因此除非对该问题有更多的参与,并描述用例,以及为什么当前的解决方法不可接受,否则它不太可能得到实施。