Reputation: 2185
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!
}
Upvotes: 3
Views: 295
Reputation: 1074949
A union between Dictionary<any>
and {[P in keyof StandardContext]?: never}
does it:
type NonStandardContext = Dictionary<any> & { [P in keyof StandardContext]?: never };
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