How to omit [key:string]: any from a type in typescript?

Viewed 3264

Say I have

interface A {
  apple?: number;
  [key: string]: any;
}

interface B extends A {
  banana?: number;
}

I want a type C to extend all from A and all from B except [key: string]: any;. I want a type D to inherit all from B except all from A.

How do I make C and D in typescript?

3 Answers

Pick all from B, remove A index signature:

type C = Pick<B, KnownKeys<B>>;

Pick all from B, exclude all from A, remove A index signature:

type D = Omit<C, KnownKeys<A>>

Type KnownKeys<T> removes the index signature of T, using only the known property keys (credit goes to Mihail Malostanidis and his answers here and here):

type KnownKeys<T> = {
    [K in keyof T]: string extends K ? never : number extends K ? never : K
} extends { [_ in keyof T]: infer U } ? U : never;

How do types C and D look like?

type C = {
    banana?: number | undefined;
    apple?: number | undefined;
}

type D = {
    banana?: number | undefined;
}

const c: C = {
    apple: 1,
    banana: 2,
}

const d: D = {
    banana: 2
}

Playground

This should work:

type NoStringIndex<T> = { [K in keyof T as string extends K ? never : K]: T[K] };

interface A {
  apple?: number;
  [key: string]: any;
}

type A2 = NoStringIndex<A>

I don't think you can do that in the way you think (exclude [key: string]: any;) in sense that to exclude a key you have to use the key or its value type.

Instead you can pick the properties you want:

type C = Pick<B, 'apple' | 'banana'>;
Related