【问题标题】:How to select a string member of an object如何选择对象的字符串成员
【发布时间】:2020-07-12 10:48:30
【问题描述】:

我有以下定义

interface IAutoCompleteInputProps<T> {
    textMember: keyof T;
    imageMember: keyof T;
    data: T[];
}

但我也想确保T[textMember] 的值也必须是string。 我怎样才能做到这一点?

=== 更新: 在我实现了@R Pasha 的答案后,当我尝试通过a.data[a.textMember] 访问textMember 时(我希望它是一个字符串),但IDE 说

(property) value: T[{ [K in keyof T]: T[K] extends string ? K : never; }[keyof T]]
Type 'T[{ [K in keyof T]: T[K] extends string ? K : never; }[keyof T]]' is not assignable to type 'string'.
  Type 'T[T[keyof T] extends string ? keyof T : never]' is not assignable to type 'string'.
    Type 'T[keyof T]' is not assignable to type 'string'.
      Type 'T[string] | T[number] | T[symbol]' is not assignable to type 'string'.
        Type 'T[string]' is not assignable to type 'string'.ts(2322)

我可以将它转换为字符串,但只是想知道为什么?谢谢

PS 我得到错误的代码

function Application<T>(props: IAutoCompleteInputProps<T>) {
  const x = props.data[0][props.textMember]; // x here is not string
}

这里是Playground Link

【问题讨论】:

    标签: typescript typescript-generics


    【解决方案1】:

    你可以使用Conditional types

    type StringProperties<T> = Pick<T, { 
        [K in keyof T]: T[K] extends string ? K : never 
    }[keyof T]>;
    
    interface IAutoCompleteInputProps<T>{
        textMember: keyof StringProperties<T>;
        imageMember: keyof T;
        data: T[];
    }
    
    interface Type1 {
      field1: number; // <- is number
      field2: string;
    }
    
    let x : IAutoCompleteInputProps<Type1> = {
      textMember : 'field1', // <- field1 must be string
      imageMember: 'field2',
      data: []
    
    }
    

    【讨论】:

    • 太棒了!这在我为道具输入值时有效,但是当我尝试提取文本成员的值时,Visual Studio 代码中仍然存在错误。我更新了问题。你知道为什么吗?
    • 嗯,很有趣。你能做一个 stackblitz.com 吗?
    • 是的,我创建了一个游乐场链接,在帖子中更新,因为链接太长了
    • 看来 Typescript 不支持这种情况,更多讨论stackoverflow.com/questions/55641731/…
    【解决方案2】:

    使用此帮助器选择字符串值的属性:

    type PropertyOfValue<T, V> = {
      [K in keyof T]-?: T[K] extends V
        ? K
        : never
    }[keyof T];
    

    用法:

    interface Type1 {
      field1: number; 
      field2: string;
    }
    
    const props: IAutoCompleteInputProps<Type1> = {
      data: [
        { field1: 42, field2: 'foo' }
      ],
      imageMember: 'field1',
      textMember: 'field2'
    }
    
    props.textMember; // "field2"
    props.data[0][props.textMember]; // string
    

    TypeScript Playground

    【讨论】:

    • 感谢@Karol Majewski,您的回答与第一个有点相似。当我在另一个Generic函数中使用它时,它仍然不能扣除到string。任何想法?我更新了我的问题
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-02-23
    • 1970-01-01
    • 2013-11-16
    • 2012-08-15
    • 1970-01-01
    • 1970-01-01
    • 2011-06-08
    相关资源
    最近更新 更多