Background
I've been using the Exclude and Extract utility types but have come across a case where i only want to match exact types not subtypes.
So far
I've managed to create a StrictExtract utility type that only extracts types that are an exact match - although there's possibly an easier way to do this?
type StrictExtract<T, U> =
T extends unknown ?
U extends T ?
T extends U ?
T :
never :
never :
never;
Examples
type objOne = {
prop1: string;
prop2: number;
}
type objTwo = {
prop1: string;
prop2: number;
prop3: Function;
}
type ext1 = Extract<objOne | objTwo | string | number, string | number | objOne>
// string | number | objOne | objTwo
type stext1 = StrictExtract<objOne | objTwo | string | number, string | number | objOne>
// string | number | objOne
So where as Extract would also match objTwo as it's a subtype of objOne, StrictExtract accepts the same type parameters, but only extracts exact type matches.
So StrictExclude would mirror the input parameters of Exclude<Type, Union>, but would only exclude types that where an exact match.
type excl = Exclude<objOne | objTwo | string | number, objOne | string | number>
// never
type strExcl = StrictExclude<objOne | objTwo | string | number, objOne | string | number>
// should result in objTwo
Problem
I've tried to use the same approach to work out the logic for StrictExclude but have been going round in circles for a while now.
I started off with the following utility to get an understanding of what's output by each condition. I can see how to calculate which types need to be removed - essentially by using StrictExtract - but not how to then remove those exact types from the union of T... (╯°□°)╯︵ ┻━┻
type StrictExclude<T, U> =
T extends unknown ?
(U extends T ?
(T extends U ?
(tok: T) => U :
(ux: U) => T) :
(u2x: U) => T) :
never;
Question
How do you create a strict exclude utility type, that only removes exact type matches, not subtypes?