如何编写一个接受通用类型为T的对象和一个字符串参数的类型保护,并检查该字符串是否为keyof T类型?

时间:2019-11-22 00:10:57

标签: typescript

我有一个MyObject类型的对象,它有两个字符串属性。

interface MyObject {
  a: number,
  b: string,
}

const myObject = {
  a: 5,
  b: 'str'
}

然后我有一个接受字符串的函数,并且我希望能够访问由string参数指定的上述对象的属性。我想做的是在访问属性之前,使用类型防护来检查字符串是否是对象的键。必须进行某种检查,因为该参数只是一个字符串,并且该对象没有索引签名。

如果我创建一个特定版本来检查这种特定类型的对象(MyObject),那么它将起作用:

// specific version
const isValidPropertyForMyObject = (property: string): property is keyof MyObject => Object.keys(myObject).indexOf(property) !== -1

const getProperty1 = (property: string) => {
  if (isValidPropertyForMyObject(property)) {
    myObject[property]
  }
}

但是,如果我希望能够传入具有泛型类型和字符串参数的对象,并检查该属性是否实际上是该对象的键,该怎么办?这是我的尝试:

const isValidMethodForHandler = <T extends { [i: string]: any }>(handler: T) => (
  method: string
): method is keyof T => Object.keys(handler).indexOf(method) !== -1;


const getProperty = (property: string) => {
  // const acceptedProperties = ["a", "b"];
  // if (acceptedProperties.indexOf(property) !== -1) {
  //   myObject[property]
  // }

  if (isValidMethodForHandler(myObject)(property)) {
    myObject[property]
  }
}

问题出在类型防护中:

  

类型谓词的类型必须可分配给其参数的类型。     类型“ keyof T”不可分配给类型“ string”。       输入'string |编号符号”不能分配给“字符串”类型。         无法将“数字”类型分配给“字符串”类型。(2677)

2 个答案:

答案 0 :(得分:0)

您当然可以写:

interface MyObject {
  a: number,
  b: string,
}

const myObject = {
  a: 5,
  b: 'str'
}
const isValidPropertyForMyObject = (property: string): property is keyof MyObject => 
     property in myObject;

然后您可以执行以下操作:

const f = <K extends keyof MyObject>(obj: MyObject, k: K): MyObject[K] => obj[k];

const g = <K extends keyof MyObject>(obj: MyObject, k: string | K): MyObject[K] | string =>
    isValidPropertyForMyObject(k) ? f(obj, k) : "NOT LEGAL";

假定存在一个常量myObject,该常量在运行时列出了​​MyObject的所有键。

答案 1 :(得分:0)

答案基于TypeScript问题跟踪程序here中的该线程。

上述问题中特定TypeScript错误的解释在this other question

我的示例代码的解决方案是:

const isValidMethodForHandler = <T extends { [i: string]: any }>(handler: T) => (
  method: string
): method is Extract<keyof T, string> => Object.keys(handler).indexOf(method) !== -1;

const getProperty = (property: string) => {
  if (isValidMethodForHandler(myObject)(property)) {
    myObject[property]
  }

keyof返回所有已知键,并且这些键均为string | number | symbol类型。

要仅获取字符串属性,请使用Extract