【问题标题】:TypeScript: Read generic type of value in objectTypeScript:读取对象中值的通用类型
【发布时间】:2019-11-01 22:58:09
【问题描述】:

我有这个界面:

interface Api {
  state: Converter<State>;
  water: Converter<Water>;
  version: Converter<Versions>;
}

我有一个名为write的函数

write(name, value);

现在我想要实现的是 value 的类型应该是 Converter 的泛型,具体取决于第一个参数 (name)。

所以如果我打电话给write("state", value) -> value 应该是State"water""version" 也是如此。

write("state, value);    // value should be type of State
write("water", value);   // value should be type of Water
write("version", value); // value should be type of Versions

我这样实现了第一个参数:

write(name: keyof Api, value: ???)

我发现我可以像这样得到keyof Api的对应值:

write<K extends keyof Api>(name: K, value: Api[K])

但这给了我Converter&lt;State&gt;"state"。有没有办法可以访问Converter 中的泛型?

【问题讨论】:

    标签: typescript generics typescript-typings typescript-generics


    【解决方案1】:

    我不知道这是否有帮助,因为我不确定您的 Converter 界面是什么样的。

    但是有了这个:

    interface Converter<T> {
      converter: T;
    }
    

    这些接口用于StateWaterVersion

    interface State {
      state: string;
    }
    
    interface Water {
      water: string;
    }
    
    interface Version {
      version: string;
    }
    

    你可以这样做:

    function write<K extends keyof Api>(name: K, value: Api[K]["converter"]) {}
    
    write("state", { state: "x" }); // Works
    
    write("water", { state: "x" }); // Argument of type '{ state: string; }' is not assignable to parameter of type 'Water'.
    
    write("water", { water: "x" }); // Works
    
    

    但它会为您的Converter 接口添加一个属性。

    【讨论】:

    • 嘿,谢谢!这就是我现在正在做的!但我必须将converter 属性设为可选,否则我必须在每次使用接口时实际设置该字段。非常感谢!
    【解决方案2】:

    如果您有权访问 Converter iterface/type 或任何使用此类型扩展它的东西

    或者像这样创建扩展接口

    interface Converter<T> {
      p1: any;
      p2: any;
    }
    interface IExtendedConverter<T> extends Converter<T> {
      type: T;
    }
    
    interface IApi {
      state: IExtendedConverter<string>;
      water: IExtendedConverter<number>;
    }
    
    const write = <K extends keyof IApi>(name: K, value: IApi[K]['type']) => {
      return;
    };
    
    const str = write('state', '1'); // here value has to be string
    const num = write('water', 1); // here value has to be number
    

    根据问题编辑

    一个解决方案是定义这个参数

    const extendedConverterState: IExtendedConverter<string> = {
      ...converter,
      type: '',
    };
    
    const extendedConverterNumber: IExtendedConverter<number> = {
      ...converter,
      type: 1,
    };
    
    const api: IApi = {
      state: extendedConverterState,
      water: extendedConverterNumber,
    };
    

    这是一种迟钝的解决方案,因为您只会创建这个永远不会使用的属性。

    其他解决方案可以是创建类型参数作为 optionla

    interface IExtendedConverter<T> extends Converter<T> {
      type?: T;
    }
    

    但是这个souliton会将你在写函数中的参数作为可选的(可能未定义)

    也许有更好的解决方案来访问这种泛型类型。身份证

    【讨论】:

    • 嘿,非常感谢!这完美无缺。但是我有一个问题:从外部来看,类型检查完全按照预期工作,但是当我创建一个 API 对象 (const api: Api = { state, water, version };) 时,TS 告诉我 statewaterversion 中的 Property 'type' is missing 。目前这些变量的类型为Converter,如果我将类型更改为IExtendedConverter ,它会告诉我Property 'type' is missing in type ,但我不知道如何定义它
    • 嘿,我将type?: T; 添加到Converter 并删除了IExtendedConverter ,并按照您的建议保留了其余部分。这对我来说非常有效。谢谢!
    猜你喜欢
    • 2023-01-19
    • 1970-01-01
    • 2019-05-08
    • 2020-07-16
    • 2021-02-07
    • 2019-12-09
    • 1970-01-01
    • 2021-10-25
    • 1970-01-01
    相关资源
    最近更新 更多