UNPKG

2.25 kBTypeScriptView Raw
1declare const invariantBrand: unique symbol;
2
3/**
4Create an [invariant type](https://basarat.gitbook.io/typescript/type-system/type-compatibility#footnote-invariance), which is a type that does not accept supertypes and subtypes.
5
6Use-case:
7- Prevent runtime errors that may occur due to assigning subtypes to supertypes.
8- Improve type signature of object methods like [`Object.keys()` or `Object.entries()`](https://github.com/microsoft/TypeScript/pull/12253#issuecomment-263132208) by sealing the object type.
9
10@example
11```
12import type {InvariantOf} from 'type-fest';
13
14class Animal {
15 constructor(public name: string){}
16}
17
18class Cat extends Animal {
19 meow() {}
20}
21
22let animalArray: Animal[] = [animal];
23let catArray: Cat[] = [cat];
24
25animalArray = catArray; // Okay if covariant
26animalArray.push(new Animal('another animal')); // Pushed an animal into catArray
27catArray.forEach(c => c.meow()); // Allowed but, error at runtime
28
29let invariantAnimalArray: InvariantOf<Animal>[] = [animal] as InvariantOf<Animal>[];
30let invariantCatArray: InvariantOf<Cat>[] = [cat] as InvariantOf<Cat>[];
31
32invariantAnimalArray = invariantCatArray; // Error: Type 'InvariantOf<Cat>[]' is not assignable to type 'InvariantOf<Animal>[]'.
33```
34
35@example
36```
37import type {InvariantOf} from 'type-fest';
38
39// In covariance (default)
40
41interface FooBar {
42 foo: number;
43 bar: string
44}
45
46interface FooBarBaz extends FooBar {
47 baz: boolean
48}
49
50declare const fooBar: FooBar
51declare const fooBarBaz: FooBarBaz
52
53function keyOfFooBar(fooBar: FooBar) {
54 return Object.keys(fooBar) as (keyof FooBar)[]
55}
56
57keyOfFooBar(fooBar) //=> (keyof FooBar)[]
58keyOfFooBar(fooBarBaz) //=> (keyof FooBar)[] but, (keyof FooBarBaz)[] at runtime
59
60// In invariance
61
62export function invariantOf<Type>(value: Type): InvariantOf<Type> {
63 return value as InvariantOf<Type>;
64}
65
66function keyOfInvariantFooBar(fooBar: InvariantOf<FooBar>) {
67 return Object.keys(fooBar) as (keyof FooBar)[]
68}
69
70keyOfInvariantFooBar(invariantOf(fooBar)); // (keyof FooBar)[]
71keyOfInvariantFooBar(invariantOf(fooBarBaz)); // Error: Argument of type 'InvariantOf<FooBarBaz>' is not assignable to parameter of type 'InvariantOf<FooBar>'.
72```
73
74@category Type
75*/
76export type InvariantOf<Type> = Type & {[invariantBrand]: (_: Type) => Type};