【问题标题】:Limit object properties to keyof interface将对象属性限制为 keyof 接口
【发布时间】:2017-11-08 23:25:17
【问题描述】:

此代码无法编译:

interface IFoo {
   a: number;
}

type TFoo = keyof IFoo;
type OFoo = { [key: TFoo]: any };

let obj: OFoo = { a: 1 };

我想要实现的是 obj 只能分配给具有有效属性的对象,就像我写的一样:

let obj: IFoo = { a: 1};

但我需要通过 keyof 来完成。

感谢您的任何想法。

【问题讨论】:

    标签: typescript


    【解决方案1】:

    虽然您不能直接使用除 stringnumber 之外的任何东西作为索引签名中的键类型(并且您对 OFoo 的定义会导致您出现这种情况的错误),但您可以 使用mapped types 将键限制为string 的子类型。由于TFoo,又名keyof Foo,是string 的子类型,您可以使用如下映射类型:

    type OFoo = { [K in TFoo]: any }; 
    

    请注意,映射类型的语法与常规索引签名的语法不同。上面的TFoo 对应于允许键的类型,在您的情况下只是"a",但也可以是字符串文字的联合,如"a"|"b"|"c",甚至string。而上面的K 是一个参数,对应于每个属性的键的type。 (您并不真正关心K,因为每个属性value 的类型是any,与K 无关,但您可以使用K 来挑选如果您愿意,可以使用特定属性。)无论如何,让我们使用它:

    let obj: OFoo = { a: 1 }; // okay
    let obj = { }; // error, property 'a' is missing
    let obj = { c: 1 }; // error, excess property 'c'
    

    顺便说一句,我可能会使用内置标准库类型Record<K,T>,它的定义如下:

    type Record<K extends string, T> = {
      [P in K]: T
    }
    

    或者,您可以认为:“Record&lt;K, T&gt; 是一个对象,其中每个键都在 K 中,每个值都是 T”。对你来说,KTFooTany

    type OFoo = Record<TFoo, any>;  // same thing 
    

    希望有所帮助;祝你好运!

    【讨论】:

    • 它应该是type OFoo = { [key in TFoo]: IFoo[key] };,否则let obj: OFoo = { a: 'hey' }; 将是类型兼容的。
    • 太好了,你在答案中提到了Record,这样的内置类型很容易被忽略!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-11-21
    • 2013-04-09
    • 2015-07-27
    • 2021-11-15
    • 1970-01-01
    • 2021-07-10
    • 2020-03-17
    相关资源
    最近更新 更多