1 | declare const invariantBrand: unique symbol;
|
2 |
|
3 | /**
|
4 | Create 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 |
|
6 | Use-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 | ```
|
12 | import type {InvariantOf} from 'type-fest';
|
13 |
|
14 | class Animal {
|
15 | constructor(public name: string){}
|
16 | }
|
17 |
|
18 | class Cat extends Animal {
|
19 | meow() {}
|
20 | }
|
21 |
|
22 | let animalArray: Animal[] = [animal];
|
23 | let catArray: Cat[] = [cat];
|
24 |
|
25 | animalArray = catArray; // Okay if covariant
|
26 | animalArray.push(new Animal('another animal')); // Pushed an animal into catArray
|
27 | catArray.forEach(c => c.meow()); // Allowed but, error at runtime
|
28 |
|
29 | let invariantAnimalArray: InvariantOf<Animal>[] = [animal] as InvariantOf<Animal>[];
|
30 | let invariantCatArray: InvariantOf<Cat>[] = [cat] as InvariantOf<Cat>[];
|
31 |
|
32 | invariantAnimalArray = invariantCatArray; // Error: Type 'InvariantOf<Cat>[]' is not assignable to type 'InvariantOf<Animal>[]'.
|
33 | ```
|
34 |
|
35 | @example
|
36 | ```
|
37 | import type {InvariantOf} from 'type-fest';
|
38 |
|
39 | // In covariance (default)
|
40 |
|
41 | interface FooBar {
|
42 | foo: number;
|
43 | bar: string
|
44 | }
|
45 |
|
46 | interface FooBarBaz extends FooBar {
|
47 | baz: boolean
|
48 | }
|
49 |
|
50 | declare const fooBar: FooBar
|
51 | declare const fooBarBaz: FooBarBaz
|
52 |
|
53 | function keyOfFooBar(fooBar: FooBar) {
|
54 | return Object.keys(fooBar) as (keyof FooBar)[]
|
55 | }
|
56 |
|
57 | keyOfFooBar(fooBar) //=> (keyof FooBar)[]
|
58 | keyOfFooBar(fooBarBaz) //=> (keyof FooBar)[] but, (keyof FooBarBaz)[] at runtime
|
59 |
|
60 | // In invariance
|
61 |
|
62 | export function invariantOf<Type>(value: Type): InvariantOf<Type> {
|
63 | return value as InvariantOf<Type>;
|
64 | }
|
65 |
|
66 | function keyOfInvariantFooBar(fooBar: InvariantOf<FooBar>) {
|
67 | return Object.keys(fooBar) as (keyof FooBar)[]
|
68 | }
|
69 |
|
70 | keyOfInvariantFooBar(invariantOf(fooBar)); // (keyof FooBar)[]
|
71 | keyOfInvariantFooBar(invariantOf(fooBarBaz)); // Error: Argument of type 'InvariantOf<FooBarBaz>' is not assignable to parameter of type 'InvariantOf<FooBar>'.
|
72 | ```
|
73 |
|
74 | @category Type
|
75 | */
|
76 | export type InvariantOf<Type> = Type & {[invariantBrand]: (_: Type) => Type};
|