TypeScript: remove index signature using mapped types

前端 未结 3 1010
失恋的感觉
失恋的感觉 2020-12-03 10:41

Given an interface (from an existing .d.ts file that can\'t be changed):

interface Foo {
  [key: string]: any;
  bar(): void;
}

Is there a

相关标签:
3条回答
  • 2020-12-03 11:28

    There is a way, requiring TypeScript 2.8's Conditional Types.

    It is based on the fact that 'a' extends string but string doesn't extends 'a'

    interface Foo {
      [key: string]: any;
      bar(): void;
    }
    
    type KnownKeys<T> = {
      [K in keyof T]: string extends K ? never : number extends K ? never : K
    } extends { [_ in keyof T]: infer U } ? U : never;
    
    
    type FooWithOnlyBar = Pick<Foo, KnownKeys<Foo>>;
    

    You can make a generic out of that:

    // Generic !!!
    type RequiredOnly<T extends Record<any,any>> = Pick<T, KnownKeys<T>>;
    
    type FooWithOnlyBar = RequiredOnly<Foo>;
    

    For an explanation of why exactly KnownKeys<T> works, see the following answer:

    https://stackoverflow.com/a/51955852/2115619

    0 讨论(0)
  • 2020-12-03 11:37

    There is not a really generic way for it, but if you know which properties you need, then you can use Pick:

    interface Foo {
      [key: string]: any;
      bar(): void;
    }
    
    type FooWithOnlyBar = Pick<Foo, 'bar'>;
    
    const abc: FooWithOnlyBar = { bar: () => { } }
    
    abc.notexisting = 5; // error
    
    0 讨论(0)
  • 2020-12-03 11:43

    Not really. You can't "subtract" something an interface like this one. Every member is public and anyone claiming to implement Foo, must implement them. In general, you can only extend interfaces, via extends or declaration merging, but not remove things from them.

    0 讨论(0)
提交回复
热议问题