【问题标题】:How do I exclude an index signature from a type? [duplicate]如何从类型中排除索引签名? [复制]
【发布时间】:2018-12-20 05:13:56
【问题描述】:

如果我如下定义我的类型,它将遵循我想要的行为。

interface Foo {}

interface Bar {
    a: string;
    b: boolean;
    c: Foo;
}

type x = keyof Bar; // "a" | "b" | "c"

但是,如果我尝试添加索引签名,它会丢失我所有的预定义成员。

interface Bar {
    [index: string]: any;
}

type x = keyof Bar; // string | number

有没有办法在 TypeScript 中正确执行此操作?

类似于:

type x = Exclude<Bar, { [index: string]: any }>; // never

编辑 我尝试了类似于 Jake 的解决方案并得到了这个:

interface Indexable<T> {
    [index: string]: any;
}
type BaseType<T> = T extends Indexable<infer U> ? U : never;

interface BaseFoo {
    Name: string;
}
interface Foo1 extends Indexable<BaseFoo> {}
type Foo2 = Indexable<BaseFoo>;

type base1 = BaseType<Foo1>; // {}
type base2 = BaseType<Foo2>; // BaseFoo

Foo1 不起作用,由于某种原因,其类型信息变为{}Foo2 确实 工作,但智能感知不会为 Foo2 类型的变量说 Foo2。他们改为Indexable&lt;BaseFoo&gt;

我真的很想尝试对我的用户隐藏这种类型的按摩。不幸的是,让他们从Indexable&lt;T&gt;T 来回转换是不可行的。

【问题讨论】:

  • 不要认为有办法做到这一点。一旦您将索引签名添加到组合keyof 将返回string ,因此您无法访问命名键并且排除索引签名也是不可能的,因为任何具有签名的条件类型约束也将匹配属性
  • TypeScript: remove index signature using mapped types 的可能重复这个问题在技术上较早(10 天),但另一个问题有答案。

标签: typescript


【解决方案1】:

回答

对于具有索引签名的东西没有通用的方法。

另类

在添加索引签名之前获取密钥

interface Foo {}

interface BarCore {
    a: string;
    b: boolean;
    c: Foo;
}


type Bar = BarCore & {
    [index: string]: any;
}

type X = keyof BarCore; // a|b|c

更多

PS:尽量不要在根级别将索引签名与有效道具混合。而是使用nested object pattern

【讨论】:

    【解决方案2】:

    不,因为这是正确的行为。 string | "x" 将简化为 string,因为 "x" extends string 为真。当您只定义 string 索引签名时,您会得到 string | number,因为 JavaScript 会将数字索引转换为对象上的字符串索引。

    如果您想要您正在寻找的行为,您将需要更改您的接口定义。

    interface Foo {}
    
    interface Bar {
        a: string;
        b: boolean;
        c: Foo;
    }
    
    interface IndexedBar extends Bar {
        [ key: string ]: any;
    }
    
    type x = keyof Bar; // "a" | "b" | "c"
    

    另请注意,在某些情况下,您不会对 IndexedBar 进行正确的类型检查。

    function setValue(obj: IndexedBar, key: string, value: any): void {
        obj[key] = value;
    }
    
    setValue(bar, "a", 4); // No error, even though a is explicitly a string.
    

    【讨论】:

    • 我认为这是我想要的大部分方式。我用更多信息更新了我的问题。谢谢!
    猜你喜欢
    • 2020-06-27
    • 1970-01-01
    • 2018-12-30
    • 2020-06-27
    • 1970-01-01
    • 2019-04-28
    • 1970-01-01
    • 1970-01-01
    • 2015-11-25
    相关资源
    最近更新 更多