File: excessPropertyCheckWithMultipleDiscriminants.ts

package info (click to toggle)
node-typescript 5.1.6%2Bds1-1
  • links: PTS, VCS
  • area: main
  • in suites: experimental
  • size: 492,516 kB
  • sloc: javascript: 2,078,951; makefile: 6; sh: 1
file content (139 lines) | stat: -rw-r--r-- 2,962 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
// Repro from #32657

interface Base<T> {
    value: T;
}

interface Int extends Base<number> {
    type: "integer";
    multipleOf?: number;
}

interface Float extends Base<number> {
    type: "number";
}

interface Str extends Base<string> {
    type: "string";
    format?: string;
}

interface Bool extends Base<boolean> {
    type: "boolean";
}

type Primitive = Int | Float | Str | Bool;

const foo: Primitive = {
    type: "number",
    value: 10,
    multipleOf: 5, // excess property
    format: "what?"
}


type DisjointDiscriminants = { p1: 'left'; p2: true; p3: number } | { p1: 'right'; p2: false; p4: string } | { p1: 'left'; p2: boolean };

// This has excess error because variant three is the only applicable case.
const a: DisjointDiscriminants = {
    p1: 'left',
    p2: false,
    p3: 42,
    p4: "hello"
};

// This has excess error because variant two is not applicable.
const b: DisjointDiscriminants = {
    p1: 'left',
    p2: true,
    p3: 42,
    p4: "hello"
};

// This has excess error because variant two is the only applicable case
const c: DisjointDiscriminants = {
    p1: 'right',
    p2: false,
    p3: 42,
    p4: "hello"
};

// Repro from #51873

interface Common {
    type: "A" | "B" | "C" | "D";
    n: number;
}
interface A {
    type: "A";
    a?: number;
}
interface B {
    type: "B";
    b?: number;
}

type CommonWithOverlappingOptionals = Common | (Common & A) | (Common & B);

// Should reject { b } because reduced to Common | (Common & A)
const c1: CommonWithOverlappingOptionals = {
    type: "A",
    n: 1,
    a: 1,
    b: 1  // excess property
}

type CommonWithDisjointOverlappingOptionals = Common | A | B;

// Should still reject { b } because reduced to Common | A, even though these are now disjoint
const c2: CommonWithDisjointOverlappingOptionals = {
    type: "A",
    n: 1,
    a: 1,
    b: 1  // excess property
}

// Repro from https://github.com/microsoft/TypeScript/pull/51884#issuecomment-1472736068

export type BaseAttribute<T> = {
    type?: string | undefined;
    required?: boolean | undefined;
    defaultsTo?: T | undefined;
};

export type Attribute =
    | string
    | StringAttribute
    | NumberAttribute
    | OneToOneAttribute

export type Attribute2 =
    | string
    | StringAttribute
    | NumberAttribute

export type StringAttribute = BaseAttribute<string> & {
    type: 'string';
};

export type NumberAttribute = BaseAttribute<number> & {
    type: 'number';
    autoIncrement?: boolean | undefined;
};

export type OneToOneAttribute = BaseAttribute<any> & {
    model: string;
};

// both should error due to excess properties
const attributes: Attribute = {
    type: 'string',
    autoIncrement: true,
    required: true,
};

const attributes2: Attribute2 = {
    type: 'string',
    autoIncrement: true,
    required: true,
};