Skip to content

Instantly share code, notes, and snippets.

@webstrand
Last active April 5, 2019 14:17
Show Gist options
  • Select an option

  • Save webstrand/f32f11c79f383b9abd7942eef60dc50d to your computer and use it in GitHub Desktop.

Select an option

Save webstrand/f32f11c79f383b9abd7942eef60dc50d to your computer and use it in GitHub Desktop.
Demonstration of Excluding<T> which emulates the subtractive type `object - T`
// Since typescript nominally types string based enums, we emulate
// the subtractive type `object - T` by making all the properties
// T optional and setting their types to a non-exported enum.
//
// The enum name is long and descriptive to help with debugging.
const enum CannotAssignToPropertyFromExcludedObject { ϕ = "ϕ" }
type Excluding<T extends object> = { [P in keyof T]?: CannotAssignToPropertyFromExcludedObject; } & { [prop: string]: any; }
// Note: If some overlap is acceptable, providing that the overlapping property extends T[P], use
// type Excluding<T extends object> = Partial<T> & { [prop: string]: any };
// Class implementation of Foo<T>
class FooImpl<T extends object> {
fooProp!: number;
protected anotherFooProp!: number;
constructor() {
}
}
// Here we use Excluding<T> to create a Foo<T> which represents
// the type of FooImpl & T, while guaranteeing that T does not
// overlap with any of FooImpl's underlying properties.
type Foo<T extends Excluding<FooImpl<{}>>> = FooImpl<T> & T;
const Foo: {
prototype: Foo<any>
new <T extends Excluding<FooImpl<{}>>>(): Foo<T>
} = FooImpl as any;
// no error, "a" and "b" do not overlap with any property
// of FooImpl.
const ex1 = new Foo<{a: string, b: string}> ();
console.log ( ex1.a ); // 123
console.log ( ex1.b ); // 'asd'
// error, "fooProp" overlaps with a property of FooImpl,
// and is therefore dangerous to allow intersection of
// T & FooImpl.
const ex2 = new Foo<{a: string, fooProp: string}>();
// Private and protected properties aren't supported, though, so
// be careful.
const ex3 = new Foo<{a: string, anotherFooProp: string}>();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment