为期望“ number | number”的属性使用通用类型值。字符串未定义”

时间:2019-05-17 08:14:20

标签: javascript reactjs typescript

此问题使用React代码,但特定于打字稿而不是react。

我正在使用一个简化的示例来尝试使它更易于阅读。我有一个组件MyList,它带有一个传递给props类型的泛型类型参数。

此泛型类型推断一个用于生成子组件的对象。我想使用T[keyof T] ||的值来键控每个子组件。其在T[]中的索引。

创建列表并使用索引没问题,但是我无法弄清楚如何正确键入listKey以便它可以与期望key的reacts number | string | undefined属性一起使用

type MyListProps<T> = {
  list: T[],
  listKey: keyof T,
  contentKey: keyof T
}

class MyList<T extends object> extends React.Component<MyListProps<T>, any> {
  public render() {
    return (
      <div>
        { this.props.list.map((value: T, index: number) => {
            const key = value[this.props.listKey];
            return (
              // Type T[keyof T] is not assignable 
              // to type 'number | string | undefined'
              <Item key={key}>{value[this.props.contentKey]}</Item>
            );
        }
      </div>
    );
  }
}

我如何推断出listKey类型可以使用泛型分配给预期的反应key道具类型?

1 个答案:

答案 0 :(得分:1)

由于您要将索引访问的结果分配给key,因此需要限制该索引操作可以返回的内容。一种方法是对T使用约束:

class MyList2<T extends Record<string, string | number >> extends React.Component<MyListProps2<T>, any> {
  public render() {
    return (
      <div>
        { this.props.list.map((value: T, index: number) => {
            const key = value[this.props.listKey];
            return (
              <Item key={key}>{value[this.props.contentKey]}</Item>
            );
        })}
      </div>
    );
  }
}

这确实有一个局限性,就是限制了您在T中可能拥有的值,这可能是一个问题(或者不取决于您的用例)。

另一个更复杂的选择是限制使用listKey返回的索引。这确实需要一个额外的类型参数,但它具有更大的灵活性:

type MyListProps<T, LK extends PropertyKey> = {
  list: Array<T & Record<LK, string>>,
  listKey: LK,
  contentKey: keyof T
}
declare const Item: React.FC<{}>

class MyList<T, LK extends PropertyKey> extends React.Component<MyListProps<T, LK>, any> {
  public render() {
    return (
      <div>
        {this.props.list.map((value, index: number) => {
          const key = value[this.props.listKey];
          return (
            <Item key={key}>{value[this.props.contentKey]}</Item>
          );
        })}
      </div>
    );
  }
}

let x = <MyList listKey="a" contentKey="a" list={[
  { a: "", b: 0, p: {} }
]} ></MyList>

或者在这种情况下,您可以放弃类型安全,而只需使用类型断言。