Zak Henry
Zak Henry

Reputation: 2185

How can I ban keys of one interface from appearing in another interface

Basically what I'm trying to achieve is prevention of certain properties of an existing object to be passed as arguments to an interface. I believe this is possible through some combination of conditional types, but having a hard time working out the right combination.

export interface Dictionary<T> {
  [index: string]: T;
}

type StandardContext = {
    myKeyOne?: string;
    myKeyTwo?: number;
}

type NonStandardContext = Exclude<Dictionary<any>, StandardContext>

const standard: StandardContext = {
    myKeyOne: '2', // ok!
}

const nonStandardError: NonStandardContext = {
    myKeyOne: '2' // should error (good so far)
}

const nonStandardGood: NonStandardContext = {
    foo: '2' // should not error, but it does!
}

Playground link

Upvotes: 3

Views: 295

Answers (1)

T.J. Crowder
T.J. Crowder

Reputation: 1074949

A union between Dictionary<any> and {[P in keyof StandardContext]?: never} does it:

type NonStandardContext = Dictionary<any> & { [P in keyof StandardContext]?: never };

On the playground

You don't need the ? on that second part with your example StandardContext, but that's only because your example StandardContext doesn't have any required properties. If it did have some, without the ? the type above would be impossible to satisfy since it would require you to have a property with type never! :-) (Example)

(Thank you kaya3 for pointing out the need for ?!)


I have to admit not fully understanding why Exclude<Dictionary<any>, StandardContext> doesn't work. :-) But I think Exclude only works for types that don't use index signatures. I could be wrong about why. I suspect that from reading this answer which says that Exclude is, roughly speaking, the following (except this is only for string keys, not string and number):

type Diff<T extends string, U extends string> = ({[P in T]: P } & {[P in U]: never } & { [x: string]: never })[T]
// −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−^^^^^^^^^^^^^^^^^^^^^^^^

Notice that last part excluding index keys.

Upvotes: 3

Related Questions