Treat void-typed properties as optional

This commit is contained in:
Ron Buckton
2020-09-28 18:08:06 -07:00
parent 3e824f18a8
commit d261d4d510
20 changed files with 751 additions and 74 deletions
+24 -4
View File
@@ -1352,6 +1352,18 @@ namespace ts {
}
}
/**
* Attempts to return the `SymbolLinks` for `symbol`, if one already exists.
* Does not allocate a symbol id or a `SymbolLinks` if it doesn't already exists.
*/
function tryGetSymbolLinks(symbol: Symbol): SymbolLinks | undefined {
if (symbol.flags & SymbolFlags.Transient) return <TransientSymbol>symbol;
return symbol.id ? symbolLinks[symbol.id] : undefined;
}
/**
* Gets or creates a `SymbolLinks` for `symbol`.
*/
function getSymbolLinks(symbol: Symbol): SymbolLinks {
if (symbol.flags & SymbolFlags.Transient) return <TransientSymbol>symbol;
const id = getSymbolId(symbol);
@@ -7666,11 +7678,11 @@ namespace ts {
function hasType(target: TypeSystemEntity, propertyName: TypeSystemPropertyName): boolean {
switch (propertyName) {
case TypeSystemPropertyName.Type:
return !!getSymbolLinks(<Symbol>target).type;
return !!tryGetSymbolLinks(<Symbol>target)?.type;
case TypeSystemPropertyName.EnumTagType:
return !!(getNodeLinks(target as JSDocEnumTag).resolvedEnumType);
case TypeSystemPropertyName.DeclaredType:
return !!getSymbolLinks(<Symbol>target).declaredType;
return !!tryGetSymbolLinks(<Symbol>target)?.declaredType;
case TypeSystemPropertyName.ResolvedBaseConstructorType:
return !!(<InterfaceType>target).resolvedBaseConstructorType;
case TypeSystemPropertyName.ResolvedReturnType:
@@ -8509,6 +8521,14 @@ namespace ts {
return links.type;
}
function isOptionalProperty(prop: Symbol) {
if (prop.flags & SymbolFlags.Optional) return true;
// We don't use `getTypeOfSymbol` here as we may be in the middle of resolving the type for `prop` and
// we shouldn't re-enter to check for `void`.
const type = tryGetSymbolLinks(prop)?.type;
return !!(type && forEachType(type, acceptsVoid));
}
function getTypeOfVariableOrParameterOrPropertyWorker(symbol: Symbol) {
// Handle prototype property
if (symbol.flags & SymbolFlags.Prototype) {
@@ -17894,7 +17914,7 @@ namespace ts {
return Ternary.False;
}
// When checking for comparability, be more lenient with optional properties.
if (!skipOptional && sourceProp.flags & SymbolFlags.Optional && !(targetProp.flags & SymbolFlags.Optional)) {
if (!skipOptional && sourceProp.flags & SymbolFlags.Optional && !isOptionalProperty(targetProp)) {
// TypeScript 1.0 spec (April 2014): 3.8.3
// S is a subtype of a type T, and T is a supertype of S if ...
// S' and T are object types and, for each member M in T..
@@ -19709,7 +19729,7 @@ namespace ts {
if (isStaticPrivateIdentifierProperty(targetProp)) {
continue;
}
if (requireOptionalProperties || !(targetProp.flags & SymbolFlags.Optional || getCheckFlags(targetProp) & CheckFlags.Partial)) {
if (requireOptionalProperties || !((getCheckFlags(targetProp) & CheckFlags.Partial) || isOptionalProperty(targetProp))) {
const sourceProp = getPropertyOfType(source, targetProp.escapedName);
if (!sourceProp) {
yield targetProp;
@@ -22,7 +22,7 @@ tests/cases/conformance/jsx/inline/index.tsx(24,48): error TS2322: Type 'import(
[e: string]: {};
}
interface Element {
__domBrand: void;
__domBrand: never;
props: {
children?: Element[];
};
@@ -42,7 +42,7 @@ tests/cases/conformance/jsx/inline/index.tsx(24,48): error TS2322: Type 'import(
[e: string]: {};
}
interface Element {
__predomBrand: void;
__predomBrand: never;
props: {
children?: Element[];
};
@@ -66,7 +66,7 @@ tests/cases/conformance/jsx/inline/index.tsx(24,48): error TS2322: Type 'import(
!!! error TS2532: Object is possibly 'undefined'.
export class MyClass implements predom.JSX.Element {
__predomBrand!: void;
__predomBrand!: never;
constructor(public props: {x: number, y: number, children?: predom.JSX.Element[]}) {}
render() {
return <p>
@@ -92,7 +92,7 @@ tests/cases/conformance/jsx/inline/index.tsx(24,48): error TS2322: Type 'import(
const DOMSFC = (props: {x: number, y: number, children?: dom.JSX.Element[]}) => <p>{props.x} + {props.y} = {props.x + props.y}{props.children}</p>;
class DOMClass implements dom.JSX.Element {
__domBrand!: void;
__domBrand!: never;
constructor(public props: {x: number, y: number, children?: dom.JSX.Element[]}) {}
render() {
return <p>{this.props.x} + {this.props.y} = {this.props.x + this.props.y}{...this.props.children}</p>;
@@ -7,7 +7,7 @@ export namespace dom {
[e: string]: {};
}
interface Element {
__domBrand: void;
__domBrand: never;
props: {
children?: Element[];
};
@@ -27,7 +27,7 @@ export namespace predom {
[e: string]: {};
}
interface Element {
__predomBrand: void;
__predomBrand: never;
props: {
children?: Element[];
};
@@ -47,7 +47,7 @@ import { predom } from "./renderer2"
export const MySFC = (props: {x: number, y: number, children?: predom.JSX.Element[]}) => <p>{props.x} + {props.y} = {props.x + props.y}{...this.props.children}</p>;
export class MyClass implements predom.JSX.Element {
__predomBrand!: void;
__predomBrand!: never;
constructor(public props: {x: number, y: number, children?: predom.JSX.Element[]}) {}
render() {
return <p>
@@ -70,7 +70,7 @@ elem = <h></h>; // Expect assignability error here
const DOMSFC = (props: {x: number, y: number, children?: dom.JSX.Element[]}) => <p>{props.x} + {props.y} = {props.x + props.y}{props.children}</p>;
class DOMClass implements dom.JSX.Element {
__domBrand!: void;
__domBrand!: never;
constructor(public props: {x: number, y: number, children?: dom.JSX.Element[]}) {}
render() {
return <p>{this.props.x} + {this.props.y} = {this.props.x + this.props.y}{...this.props.children}</p>;
@@ -14,11 +14,11 @@ export namespace dom {
interface Element {
>Element : Symbol(Element, Decl(renderer.d.ts, 4, 9))
__domBrand: void;
__domBrand: never;
>__domBrand : Symbol(Element.__domBrand, Decl(renderer.d.ts, 5, 27))
props: {
>props : Symbol(Element.props, Decl(renderer.d.ts, 6, 29))
>props : Symbol(Element.props, Decl(renderer.d.ts, 6, 30))
children?: Element[];
>children : Symbol(children, Decl(renderer.d.ts, 7, 20))
@@ -65,11 +65,11 @@ export namespace predom {
interface Element {
>Element : Symbol(Element, Decl(renderer2.d.ts, 4, 9))
__predomBrand: void;
__predomBrand: never;
>__predomBrand : Symbol(Element.__predomBrand, Decl(renderer2.d.ts, 5, 27))
props: {
>props : Symbol(Element.props, Decl(renderer2.d.ts, 6, 32))
>props : Symbol(Element.props, Decl(renderer2.d.ts, 6, 33))
children?: Element[];
>children : Symbol(children, Decl(renderer2.d.ts, 7, 20))
@@ -137,7 +137,7 @@ export class MyClass implements predom.JSX.Element {
>JSX : Symbol(predom.JSX, Decl(renderer2.d.ts, 0, 25))
>Element : Symbol(predom.JSX.Element, Decl(renderer2.d.ts, 4, 9))
__predomBrand!: void;
__predomBrand!: never;
>__predomBrand : Symbol(MyClass.__predomBrand, Decl(component.tsx, 5, 52))
constructor(public props: {x: number, y: number, children?: predom.JSX.Element[]}) {}
@@ -260,7 +260,7 @@ class DOMClass implements dom.JSX.Element {
>JSX : Symbol(dom.JSX, Decl(renderer.d.ts, 0, 22))
>Element : Symbol(dom.JSX.Element, Decl(renderer.d.ts, 4, 9))
__domBrand!: void;
__domBrand!: never;
>__domBrand : Symbol(DOMClass.__domBrand, Decl(index.tsx, 8, 43))
constructor(public props: {x: number, y: number, children?: dom.JSX.Element[]}) {}
@@ -6,8 +6,8 @@ export namespace dom {
>e : string
}
interface Element {
__domBrand: void;
>__domBrand : void
__domBrand: never;
>__domBrand : never
props: {
>props : { children?: Element[]; }
@@ -41,8 +41,8 @@ export namespace predom {
>e : string
}
interface Element {
__predomBrand: void;
>__predomBrand : void
__predomBrand: never;
>__predomBrand : never
props: {
>props : { children?: Element[]; }
@@ -110,8 +110,8 @@ export class MyClass implements predom.JSX.Element {
>predom : () => predom.JSX.Element
>JSX : any
__predomBrand!: void;
>__predomBrand : void
__predomBrand!: never;
>__predomBrand : never
constructor(public props: {x: number, y: number, children?: predom.JSX.Element[]}) {}
>props : { x: number; y: number; children?: predom.JSX.Element[]; }
@@ -246,8 +246,8 @@ class DOMClass implements dom.JSX.Element {
>dom : () => dom.JSX.Element
>JSX : any
__domBrand!: void;
>__domBrand : void
__domBrand!: never;
>__domBrand : never
constructor(public props: {x: number, y: number, children?: dom.JSX.Element[]}) {}
>props : { x: number; y: number; children?: dom.JSX.Element[]; }
@@ -8,7 +8,7 @@ tests/cases/conformance/jsx/inline/index.tsx(5,1): error TS2741: Property '__pre
[e: string]: {};
}
interface Element {
__domBrand: void;
__domBrand: never;
children: Element[];
props: {};
}
@@ -24,7 +24,7 @@ tests/cases/conformance/jsx/inline/index.tsx(5,1): error TS2741: Property '__pre
[e: string]: {};
}
interface Element {
__predomBrand: void;
__predomBrand: never;
children: Element[];
props: {};
}
@@ -7,7 +7,7 @@ declare global {
[e: string]: {};
}
interface Element {
__domBrand: void;
__domBrand: never;
children: Element[];
props: {};
}
@@ -23,7 +23,7 @@ export namespace predom {
[e: string]: {};
}
interface Element {
__predomBrand: void;
__predomBrand: never;
children: Element[];
props: {};
}
@@ -14,11 +14,11 @@ declare global {
interface Element {
>Element : Symbol(Element, Decl(renderer.d.ts, 4, 9))
__domBrand: void;
__domBrand: never;
>__domBrand : Symbol(Element.__domBrand, Decl(renderer.d.ts, 5, 27))
children: Element[];
>children : Symbol(Element.children, Decl(renderer.d.ts, 6, 29))
>children : Symbol(Element.children, Decl(renderer.d.ts, 6, 30))
>Element : Symbol(Element, Decl(renderer.d.ts, 4, 9))
props: {};
@@ -54,11 +54,11 @@ export namespace predom {
interface Element {
>Element : Symbol(Element, Decl(renderer2.d.ts, 4, 9))
__predomBrand: void;
__predomBrand: never;
>__predomBrand : Symbol(Element.__predomBrand, Decl(renderer2.d.ts, 5, 27))
children: Element[];
>children : Symbol(Element.children, Decl(renderer2.d.ts, 6, 32))
>children : Symbol(Element.children, Decl(renderer2.d.ts, 6, 33))
>Element : Symbol(Element, Decl(renderer2.d.ts, 4, 9))
props: {};
@@ -8,8 +8,8 @@ declare global {
>e : string
}
interface Element {
__domBrand: void;
>__domBrand : void
__domBrand: never;
>__domBrand : never
children: Element[];
>children : Element[]
@@ -36,8 +36,8 @@ export namespace predom {
>e : string
}
interface Element {
__predomBrand: void;
>__predomBrand : void
__predomBrand: never;
>__predomBrand : never
children: Element[];
>children : Element[]
@@ -264,9 +264,9 @@ tests/cases/compiler/strictFunctionTypesErrors.ts(155,5): error TS2322: Type '(c
i4 = i2; // Ok
i4 = i3; // Ok
interface Animal { animal: void }
interface Dog extends Animal { dog: void }
interface Cat extends Animal { cat: void }
interface Animal { animal: never }
interface Dog extends Animal { dog: never }
interface Cat extends Animal { cat: never }
interface Comparer1<T> {
compare(a: T, b: T): number;
@@ -88,9 +88,9 @@ i4 = i1; // Ok
i4 = i2; // Ok
i4 = i3; // Ok
interface Animal { animal: void }
interface Dog extends Animal { dog: void }
interface Cat extends Animal { cat: void }
interface Animal { animal: never }
interface Dog extends Animal { dog: never }
interface Cat extends Animal { cat: never }
interface Comparer1<T> {
compare(a: T, b: T): number;
@@ -290,22 +290,22 @@ i4 = i3; // Ok
>i4 : Symbol(i4, Decl(strictFunctionTypesErrors.ts, 71, 11))
>i3 : Symbol(i3, Decl(strictFunctionTypesErrors.ts, 70, 11))
interface Animal { animal: void }
interface Animal { animal: never }
>Animal : Symbol(Animal, Decl(strictFunctionTypesErrors.ts, 87, 8))
>animal : Symbol(Animal.animal, Decl(strictFunctionTypesErrors.ts, 89, 18))
interface Dog extends Animal { dog: void }
>Dog : Symbol(Dog, Decl(strictFunctionTypesErrors.ts, 89, 33))
interface Dog extends Animal { dog: never }
>Dog : Symbol(Dog, Decl(strictFunctionTypesErrors.ts, 89, 34))
>Animal : Symbol(Animal, Decl(strictFunctionTypesErrors.ts, 87, 8))
>dog : Symbol(Dog.dog, Decl(strictFunctionTypesErrors.ts, 90, 30))
interface Cat extends Animal { cat: void }
>Cat : Symbol(Cat, Decl(strictFunctionTypesErrors.ts, 90, 42))
interface Cat extends Animal { cat: never }
>Cat : Symbol(Cat, Decl(strictFunctionTypesErrors.ts, 90, 43))
>Animal : Symbol(Animal, Decl(strictFunctionTypesErrors.ts, 87, 8))
>cat : Symbol(Cat.cat, Decl(strictFunctionTypesErrors.ts, 91, 30))
interface Comparer1<T> {
>Comparer1 : Symbol(Comparer1, Decl(strictFunctionTypesErrors.ts, 91, 42))
>Comparer1 : Symbol(Comparer1, Decl(strictFunctionTypesErrors.ts, 91, 43))
>T : Symbol(T, Decl(strictFunctionTypesErrors.ts, 93, 20))
compare(a: T, b: T): number;
@@ -318,13 +318,13 @@ interface Comparer1<T> {
declare let animalComparer1: Comparer1<Animal>;
>animalComparer1 : Symbol(animalComparer1, Decl(strictFunctionTypesErrors.ts, 97, 11))
>Comparer1 : Symbol(Comparer1, Decl(strictFunctionTypesErrors.ts, 91, 42))
>Comparer1 : Symbol(Comparer1, Decl(strictFunctionTypesErrors.ts, 91, 43))
>Animal : Symbol(Animal, Decl(strictFunctionTypesErrors.ts, 87, 8))
declare let dogComparer1: Comparer1<Dog>;
>dogComparer1 : Symbol(dogComparer1, Decl(strictFunctionTypesErrors.ts, 98, 11))
>Comparer1 : Symbol(Comparer1, Decl(strictFunctionTypesErrors.ts, 91, 42))
>Dog : Symbol(Dog, Decl(strictFunctionTypesErrors.ts, 89, 33))
>Comparer1 : Symbol(Comparer1, Decl(strictFunctionTypesErrors.ts, 91, 43))
>Dog : Symbol(Dog, Decl(strictFunctionTypesErrors.ts, 89, 34))
animalComparer1 = dogComparer1; // Ok
>animalComparer1 : Symbol(animalComparer1, Decl(strictFunctionTypesErrors.ts, 97, 11))
@@ -354,7 +354,7 @@ declare let animalComparer2: Comparer2<Animal>;
declare let dogComparer2: Comparer2<Dog>;
>dogComparer2 : Symbol(dogComparer2, Decl(strictFunctionTypesErrors.ts, 108, 11))
>Comparer2 : Symbol(Comparer2, Decl(strictFunctionTypesErrors.ts, 101, 31))
>Dog : Symbol(Dog, Decl(strictFunctionTypesErrors.ts, 89, 33))
>Dog : Symbol(Dog, Decl(strictFunctionTypesErrors.ts, 89, 34))
animalComparer2 = dogComparer2; // Error
>animalComparer2 : Symbol(animalComparer2, Decl(strictFunctionTypesErrors.ts, 107, 11))
@@ -388,7 +388,7 @@ declare let animalCrate: Crate<Animal>;
declare let dogCrate: Crate<Dog>;
>dogCrate : Symbol(dogCrate, Decl(strictFunctionTypesErrors.ts, 121, 11))
>Crate : Symbol(Crate, Decl(strictFunctionTypesErrors.ts, 111, 31))
>Dog : Symbol(Dog, Decl(strictFunctionTypesErrors.ts, 89, 33))
>Dog : Symbol(Dog, Decl(strictFunctionTypesErrors.ts, 89, 34))
// Errors below should elaborate the reason for invariance
@@ -413,8 +413,8 @@ declare let fc2: (f: (x: Dog) => Dog) => void;
>fc2 : Symbol(fc2, Decl(strictFunctionTypesErrors.ts, 131, 11))
>f : Symbol(f, Decl(strictFunctionTypesErrors.ts, 131, 18))
>x : Symbol(x, Decl(strictFunctionTypesErrors.ts, 131, 22))
>Dog : Symbol(Dog, Decl(strictFunctionTypesErrors.ts, 89, 33))
>Dog : Symbol(Dog, Decl(strictFunctionTypesErrors.ts, 89, 33))
>Dog : Symbol(Dog, Decl(strictFunctionTypesErrors.ts, 89, 34))
>Dog : Symbol(Dog, Decl(strictFunctionTypesErrors.ts, 89, 34))
fc1 = fc2; // Error
>fc1 : Symbol(fc1, Decl(strictFunctionTypesErrors.ts, 130, 11))
@@ -442,7 +442,7 @@ namespace n1 {
static f2(x: Dog): Animal { throw "wat"; };
>f2 : Symbol(Foo.f2, Decl(strictFunctionTypesErrors.ts, 140, 53))
>x : Symbol(x, Decl(strictFunctionTypesErrors.ts, 141, 18))
>Dog : Symbol(Dog, Decl(strictFunctionTypesErrors.ts, 89, 33))
>Dog : Symbol(Dog, Decl(strictFunctionTypesErrors.ts, 89, 34))
>Animal : Symbol(Animal, Decl(strictFunctionTypesErrors.ts, 87, 8))
}
declare let f1: (cb: typeof Foo.f1) => void;
@@ -491,7 +491,7 @@ namespace n2 {
>f2 : Symbol(f2, Decl(strictFunctionTypesErrors.ts, 152, 15))
>cb : Symbol(cb, Decl(strictFunctionTypesErrors.ts, 152, 21))
>BivariantHack : Symbol(BivariantHack, Decl(strictFunctionTypesErrors.ts, 149, 14))
>Dog : Symbol(Dog, Decl(strictFunctionTypesErrors.ts, 89, 33))
>Dog : Symbol(Dog, Decl(strictFunctionTypesErrors.ts, 89, 34))
>Animal : Symbol(Animal, Decl(strictFunctionTypesErrors.ts, 87, 8))
f1 = f2;
@@ -298,14 +298,14 @@ i4 = i3; // Ok
>i4 : Func<string, Func<string, void>>
>i3 : Func<string, Func<Object, void>>
interface Animal { animal: void }
>animal : void
interface Animal { animal: never }
>animal : never
interface Dog extends Animal { dog: void }
>dog : void
interface Dog extends Animal { dog: never }
>dog : never
interface Cat extends Animal { cat: void }
>cat : void
interface Cat extends Animal { cat: never }
>cat : never
interface Comparer1<T> {
compare(a: T, b: T): number;
@@ -0,0 +1,136 @@
tests/cases/conformance/types/members/typesWithVoidProperty.ts(16,1): error TS2322: Type 'X<void>' is not assignable to type 'X<number>'.
Type 'void' is not assignable to type 'number'.
tests/cases/conformance/types/members/typesWithVoidProperty.ts(17,1): error TS2322: Type 'X<number | void>' is not assignable to type 'X<number>'.
Type 'number | void' is not assignable to type 'number'.
Type 'void' is not assignable to type 'number'.
tests/cases/conformance/types/members/typesWithVoidProperty.ts(18,1): error TS2322: Type 'Y<number>' is not assignable to type 'X<number>'.
Types of property 'value' are incompatible.
Type 'number | undefined' is not assignable to type 'number'.
Type 'undefined' is not assignable to type 'number'.
tests/cases/conformance/types/members/typesWithVoidProperty.ts(19,1): error TS2741: Property 'value' is missing in type '{ done: true; }' but required in type 'X<number>'.
tests/cases/conformance/types/members/typesWithVoidProperty.ts(21,19): error TS2322: Type 'undefined' is not assignable to type 'number'.
tests/cases/conformance/types/members/typesWithVoidProperty.ts(22,19): error TS2322: Type 'undefined' is not assignable to type 'number'.
tests/cases/conformance/types/members/typesWithVoidProperty.ts(23,19): error TS2322: Type 'void' is not assignable to type 'number'.
tests/cases/conformance/types/members/typesWithVoidProperty.ts(25,1): error TS2322: Type 'X<number>' is not assignable to type 'X<void>'.
Type 'number' is not assignable to type 'void'.
tests/cases/conformance/types/members/typesWithVoidProperty.ts(26,1): error TS2322: Type 'X<number | void>' is not assignable to type 'X<void>'.
Type 'number | void' is not assignable to type 'void'.
Type 'number' is not assignable to type 'void'.
tests/cases/conformance/types/members/typesWithVoidProperty.ts(27,1): error TS2322: Type 'Y<number>' is not assignable to type 'X<void>'.
Types of property 'value' are incompatible.
Type 'number | undefined' is not assignable to type 'void'.
Type 'number' is not assignable to type 'void'.
tests/cases/conformance/types/members/typesWithVoidProperty.ts(29,19): error TS2322: Type 'number' is not assignable to type 'void'.
tests/cases/conformance/types/members/typesWithVoidProperty.ts(44,1): error TS2322: Type 'X<void>' is not assignable to type 'Y<number>'.
Types of property 'value' are incompatible.
Type 'void' is not assignable to type 'number | undefined'.
tests/cases/conformance/types/members/typesWithVoidProperty.ts(45,1): error TS2322: Type 'X<number | void>' is not assignable to type 'Y<number>'.
Types of property 'value' are incompatible.
Type 'number | void' is not assignable to type 'number | undefined'.
Type 'void' is not assignable to type 'number | undefined'.
tests/cases/conformance/types/members/typesWithVoidProperty.ts(50,19): error TS2322: Type 'void' is not assignable to type 'number | undefined'.
==== tests/cases/conformance/types/members/typesWithVoidProperty.ts (14 errors) ====
interface X<T> {
done: true;
value: T;
}
interface Y<T> {
done: true;
value?: T;
}
declare let a: X<number>;
declare let b: X<void>;
declare let c: X<number | void>;
declare let d: Y<number>;
a = b; // not allowed because `value` must be `number`
~
!!! error TS2322: Type 'X<void>' is not assignable to type 'X<number>'.
!!! error TS2322: Type 'void' is not assignable to type 'number'.
a = c; // not allowed because `value` must be `number`
~
!!! error TS2322: Type 'X<number | void>' is not assignable to type 'X<number>'.
!!! error TS2322: Type 'number | void' is not assignable to type 'number'.
!!! error TS2322: Type 'void' is not assignable to type 'number'.
a = d; // not allowed because `value` must be `number`
~
!!! error TS2322: Type 'Y<number>' is not assignable to type 'X<number>'.
!!! error TS2322: Types of property 'value' are incompatible.
!!! error TS2322: Type 'number | undefined' is not assignable to type 'number'.
!!! error TS2322: Type 'undefined' is not assignable to type 'number'.
a = { done: true }; // not allowed because `value` is not optional (non-`void`)
~
!!! error TS2741: Property 'value' is missing in type '{ done: true; }' but required in type 'X<number>'.
!!! related TS2728 tests/cases/conformance/types/members/typesWithVoidProperty.ts:3:5: 'value' is declared here.
a = { done: true, value: 1 }; // allowed because `value` must be `number`
a = { done: true, value: undefined }; // not allowed because `value` must be `number`
~~~~~
!!! error TS2322: Type 'undefined' is not assignable to type 'number'.
!!! related TS6500 tests/cases/conformance/types/members/typesWithVoidProperty.ts:3:5: The expected type comes from property 'value' which is declared here on type 'X<number>'
a = { done: true, value: undefined as undefined }; // not allowed because `value` must be `number`
~~~~~
!!! error TS2322: Type 'undefined' is not assignable to type 'number'.
!!! related TS6500 tests/cases/conformance/types/members/typesWithVoidProperty.ts:3:5: The expected type comes from property 'value' which is declared here on type 'X<number>'
a = { done: true, value: undefined as void }; // not allowed because `value` must be `number`
~~~~~
!!! error TS2322: Type 'void' is not assignable to type 'number'.
!!! related TS6500 tests/cases/conformance/types/members/typesWithVoidProperty.ts:3:5: The expected type comes from property 'value' which is declared here on type 'X<number>'
b = a; // not allowed because `value` must be `void`
~
!!! error TS2322: Type 'X<number>' is not assignable to type 'X<void>'.
!!! error TS2322: Type 'number' is not assignable to type 'void'.
b = c; // not allowed because `value` must be `void`
~
!!! error TS2322: Type 'X<number | void>' is not assignable to type 'X<void>'.
!!! error TS2322: Type 'number | void' is not assignable to type 'void'.
!!! error TS2322: Type 'number' is not assignable to type 'void'.
b = d; // not allowed because `value` must be `void`
~
!!! error TS2322: Type 'Y<number>' is not assignable to type 'X<void>'.
!!! error TS2322: Types of property 'value' are incompatible.
!!! error TS2322: Type 'number | undefined' is not assignable to type 'void'.
!!! error TS2322: Type 'number' is not assignable to type 'void'.
b = { done: true }; // allowed because `value` is optional due to `void`
b = { done: true, value: 1 }; // not allowed because `value` must be `void`
~~~~~
!!! error TS2322: Type 'number' is not assignable to type 'void'.
!!! related TS6500 tests/cases/conformance/types/members/typesWithVoidProperty.ts:3:5: The expected type comes from property 'value' which is declared here on type 'X<void>'
b = { done: true, value: undefined }; // allowed because `value` can be `undefined` (assignable to `void`)
b = { done: true, value: undefined as undefined }; // allowed because `value` can be `undefined` (assignable to `void`)
b = { done: true, value: undefined as void }; // allowed because `value` must be `void`
c = a; // allowed because `value` can be `number`
c = b; // allowed because `value` can be `void`
c = d; // allowed because `value` can be `undefined`
c = { done: true }; // allowed because `value` is optional due to `void`
c = { done: true, value: 1 }; // allowed because `value` can be `number`
c = { done: true, value: undefined }; // allowed because `value` can be `undefined` (assignable to `void`)
c = { done: true, value: undefined as undefined }; // allowed because `value` can be `undefined` (assignable to `void`)
c = { done: true, value: undefined as void }; // allowed because `value` can be `void`
d = a; // allowed because `value` must be `number | void`
d = b; // not allowed because `value` must be `undefined`, and `void` is a supertype of `undefined`
~
!!! error TS2322: Type 'X<void>' is not assignable to type 'Y<number>'.
!!! error TS2322: Types of property 'value' are incompatible.
!!! error TS2322: Type 'void' is not assignable to type 'number | undefined'.
d = c; // not allowed allowed because `value` must be `undefined`, and `void` is a supertype of `undefined`
~
!!! error TS2322: Type 'X<number | void>' is not assignable to type 'Y<number>'.
!!! error TS2322: Types of property 'value' are incompatible.
!!! error TS2322: Type 'number | void' is not assignable to type 'number | undefined'.
!!! error TS2322: Type 'void' is not assignable to type 'number | undefined'.
d = { done: true }; // allowed because `value` is optional
d = { done: true, value: 1 }; // allowed because `value` can be `number`
d = { done: true, value: undefined }; // allowed because `value` can be `undefined`
d = { done: true, value: undefined as undefined }; // allowed because `value` can be `undefined`
d = { done: true, value: undefined as void }; // not allowed because `value` can be `undefined`, and `void` is a supertype of `undefined
~~~~~
!!! error TS2322: Type 'void' is not assignable to type 'number | undefined'.
!!! related TS6500 tests/cases/conformance/types/members/typesWithVoidProperty.ts:8:5: The expected type comes from property 'value' which is declared here on type 'Y<number>'
@@ -0,0 +1,197 @@
=== tests/cases/conformance/types/members/typesWithVoidProperty.ts ===
interface X<T> {
>X : Symbol(X, Decl(typesWithVoidProperty.ts, 0, 0))
>T : Symbol(T, Decl(typesWithVoidProperty.ts, 0, 12))
done: true;
>done : Symbol(X.done, Decl(typesWithVoidProperty.ts, 0, 16))
value: T;
>value : Symbol(X.value, Decl(typesWithVoidProperty.ts, 1, 15))
>T : Symbol(T, Decl(typesWithVoidProperty.ts, 0, 12))
}
interface Y<T> {
>Y : Symbol(Y, Decl(typesWithVoidProperty.ts, 3, 1))
>T : Symbol(T, Decl(typesWithVoidProperty.ts, 5, 12))
done: true;
>done : Symbol(Y.done, Decl(typesWithVoidProperty.ts, 5, 16))
value?: T;
>value : Symbol(Y.value, Decl(typesWithVoidProperty.ts, 6, 15))
>T : Symbol(T, Decl(typesWithVoidProperty.ts, 5, 12))
}
declare let a: X<number>;
>a : Symbol(a, Decl(typesWithVoidProperty.ts, 10, 11))
>X : Symbol(X, Decl(typesWithVoidProperty.ts, 0, 0))
declare let b: X<void>;
>b : Symbol(b, Decl(typesWithVoidProperty.ts, 11, 11))
>X : Symbol(X, Decl(typesWithVoidProperty.ts, 0, 0))
declare let c: X<number | void>;
>c : Symbol(c, Decl(typesWithVoidProperty.ts, 12, 11))
>X : Symbol(X, Decl(typesWithVoidProperty.ts, 0, 0))
declare let d: Y<number>;
>d : Symbol(d, Decl(typesWithVoidProperty.ts, 13, 11))
>Y : Symbol(Y, Decl(typesWithVoidProperty.ts, 3, 1))
a = b; // not allowed because `value` must be `number`
>a : Symbol(a, Decl(typesWithVoidProperty.ts, 10, 11))
>b : Symbol(b, Decl(typesWithVoidProperty.ts, 11, 11))
a = c; // not allowed because `value` must be `number`
>a : Symbol(a, Decl(typesWithVoidProperty.ts, 10, 11))
>c : Symbol(c, Decl(typesWithVoidProperty.ts, 12, 11))
a = d; // not allowed because `value` must be `number`
>a : Symbol(a, Decl(typesWithVoidProperty.ts, 10, 11))
>d : Symbol(d, Decl(typesWithVoidProperty.ts, 13, 11))
a = { done: true }; // not allowed because `value` is not optional (non-`void`)
>a : Symbol(a, Decl(typesWithVoidProperty.ts, 10, 11))
>done : Symbol(done, Decl(typesWithVoidProperty.ts, 18, 5))
a = { done: true, value: 1 }; // allowed because `value` must be `number`
>a : Symbol(a, Decl(typesWithVoidProperty.ts, 10, 11))
>done : Symbol(done, Decl(typesWithVoidProperty.ts, 19, 5))
>value : Symbol(value, Decl(typesWithVoidProperty.ts, 19, 17))
a = { done: true, value: undefined }; // not allowed because `value` must be `number`
>a : Symbol(a, Decl(typesWithVoidProperty.ts, 10, 11))
>done : Symbol(done, Decl(typesWithVoidProperty.ts, 20, 5))
>value : Symbol(value, Decl(typesWithVoidProperty.ts, 20, 17))
>undefined : Symbol(undefined)
a = { done: true, value: undefined as undefined }; // not allowed because `value` must be `number`
>a : Symbol(a, Decl(typesWithVoidProperty.ts, 10, 11))
>done : Symbol(done, Decl(typesWithVoidProperty.ts, 21, 5))
>value : Symbol(value, Decl(typesWithVoidProperty.ts, 21, 17))
>undefined : Symbol(undefined)
a = { done: true, value: undefined as void }; // not allowed because `value` must be `number`
>a : Symbol(a, Decl(typesWithVoidProperty.ts, 10, 11))
>done : Symbol(done, Decl(typesWithVoidProperty.ts, 22, 5))
>value : Symbol(value, Decl(typesWithVoidProperty.ts, 22, 17))
>undefined : Symbol(undefined)
b = a; // not allowed because `value` must be `void`
>b : Symbol(b, Decl(typesWithVoidProperty.ts, 11, 11))
>a : Symbol(a, Decl(typesWithVoidProperty.ts, 10, 11))
b = c; // not allowed because `value` must be `void`
>b : Symbol(b, Decl(typesWithVoidProperty.ts, 11, 11))
>c : Symbol(c, Decl(typesWithVoidProperty.ts, 12, 11))
b = d; // not allowed because `value` must be `void`
>b : Symbol(b, Decl(typesWithVoidProperty.ts, 11, 11))
>d : Symbol(d, Decl(typesWithVoidProperty.ts, 13, 11))
b = { done: true }; // allowed because `value` is optional due to `void`
>b : Symbol(b, Decl(typesWithVoidProperty.ts, 11, 11))
>done : Symbol(done, Decl(typesWithVoidProperty.ts, 27, 5))
b = { done: true, value: 1 }; // not allowed because `value` must be `void`
>b : Symbol(b, Decl(typesWithVoidProperty.ts, 11, 11))
>done : Symbol(done, Decl(typesWithVoidProperty.ts, 28, 5))
>value : Symbol(value, Decl(typesWithVoidProperty.ts, 28, 17))
b = { done: true, value: undefined }; // allowed because `value` can be `undefined` (assignable to `void`)
>b : Symbol(b, Decl(typesWithVoidProperty.ts, 11, 11))
>done : Symbol(done, Decl(typesWithVoidProperty.ts, 29, 5))
>value : Symbol(value, Decl(typesWithVoidProperty.ts, 29, 17))
>undefined : Symbol(undefined)
b = { done: true, value: undefined as undefined }; // allowed because `value` can be `undefined` (assignable to `void`)
>b : Symbol(b, Decl(typesWithVoidProperty.ts, 11, 11))
>done : Symbol(done, Decl(typesWithVoidProperty.ts, 30, 5))
>value : Symbol(value, Decl(typesWithVoidProperty.ts, 30, 17))
>undefined : Symbol(undefined)
b = { done: true, value: undefined as void }; // allowed because `value` must be `void`
>b : Symbol(b, Decl(typesWithVoidProperty.ts, 11, 11))
>done : Symbol(done, Decl(typesWithVoidProperty.ts, 31, 5))
>value : Symbol(value, Decl(typesWithVoidProperty.ts, 31, 17))
>undefined : Symbol(undefined)
c = a; // allowed because `value` can be `number`
>c : Symbol(c, Decl(typesWithVoidProperty.ts, 12, 11))
>a : Symbol(a, Decl(typesWithVoidProperty.ts, 10, 11))
c = b; // allowed because `value` can be `void`
>c : Symbol(c, Decl(typesWithVoidProperty.ts, 12, 11))
>b : Symbol(b, Decl(typesWithVoidProperty.ts, 11, 11))
c = d; // allowed because `value` can be `undefined`
>c : Symbol(c, Decl(typesWithVoidProperty.ts, 12, 11))
>d : Symbol(d, Decl(typesWithVoidProperty.ts, 13, 11))
c = { done: true }; // allowed because `value` is optional due to `void`
>c : Symbol(c, Decl(typesWithVoidProperty.ts, 12, 11))
>done : Symbol(done, Decl(typesWithVoidProperty.ts, 36, 5))
c = { done: true, value: 1 }; // allowed because `value` can be `number`
>c : Symbol(c, Decl(typesWithVoidProperty.ts, 12, 11))
>done : Symbol(done, Decl(typesWithVoidProperty.ts, 37, 5))
>value : Symbol(value, Decl(typesWithVoidProperty.ts, 37, 17))
c = { done: true, value: undefined }; // allowed because `value` can be `undefined` (assignable to `void`)
>c : Symbol(c, Decl(typesWithVoidProperty.ts, 12, 11))
>done : Symbol(done, Decl(typesWithVoidProperty.ts, 38, 5))
>value : Symbol(value, Decl(typesWithVoidProperty.ts, 38, 17))
>undefined : Symbol(undefined)
c = { done: true, value: undefined as undefined }; // allowed because `value` can be `undefined` (assignable to `void`)
>c : Symbol(c, Decl(typesWithVoidProperty.ts, 12, 11))
>done : Symbol(done, Decl(typesWithVoidProperty.ts, 39, 5))
>value : Symbol(value, Decl(typesWithVoidProperty.ts, 39, 17))
>undefined : Symbol(undefined)
c = { done: true, value: undefined as void }; // allowed because `value` can be `void`
>c : Symbol(c, Decl(typesWithVoidProperty.ts, 12, 11))
>done : Symbol(done, Decl(typesWithVoidProperty.ts, 40, 5))
>value : Symbol(value, Decl(typesWithVoidProperty.ts, 40, 17))
>undefined : Symbol(undefined)
d = a; // allowed because `value` must be `number | void`
>d : Symbol(d, Decl(typesWithVoidProperty.ts, 13, 11))
>a : Symbol(a, Decl(typesWithVoidProperty.ts, 10, 11))
d = b; // not allowed because `value` must be `undefined`, and `void` is a supertype of `undefined`
>d : Symbol(d, Decl(typesWithVoidProperty.ts, 13, 11))
>b : Symbol(b, Decl(typesWithVoidProperty.ts, 11, 11))
d = c; // not allowed allowed because `value` must be `undefined`, and `void` is a supertype of `undefined`
>d : Symbol(d, Decl(typesWithVoidProperty.ts, 13, 11))
>c : Symbol(c, Decl(typesWithVoidProperty.ts, 12, 11))
d = { done: true }; // allowed because `value` is optional
>d : Symbol(d, Decl(typesWithVoidProperty.ts, 13, 11))
>done : Symbol(done, Decl(typesWithVoidProperty.ts, 45, 5))
d = { done: true, value: 1 }; // allowed because `value` can be `number`
>d : Symbol(d, Decl(typesWithVoidProperty.ts, 13, 11))
>done : Symbol(done, Decl(typesWithVoidProperty.ts, 46, 5))
>value : Symbol(value, Decl(typesWithVoidProperty.ts, 46, 17))
d = { done: true, value: undefined }; // allowed because `value` can be `undefined`
>d : Symbol(d, Decl(typesWithVoidProperty.ts, 13, 11))
>done : Symbol(done, Decl(typesWithVoidProperty.ts, 47, 5))
>value : Symbol(value, Decl(typesWithVoidProperty.ts, 47, 17))
>undefined : Symbol(undefined)
d = { done: true, value: undefined as undefined }; // allowed because `value` can be `undefined`
>d : Symbol(d, Decl(typesWithVoidProperty.ts, 13, 11))
>done : Symbol(done, Decl(typesWithVoidProperty.ts, 48, 5))
>value : Symbol(value, Decl(typesWithVoidProperty.ts, 48, 17))
>undefined : Symbol(undefined)
d = { done: true, value: undefined as void }; // not allowed because `value` can be `undefined`, and `void` is a supertype of `undefined
>d : Symbol(d, Decl(typesWithVoidProperty.ts, 13, 11))
>done : Symbol(done, Decl(typesWithVoidProperty.ts, 49, 5))
>value : Symbol(value, Decl(typesWithVoidProperty.ts, 49, 17))
>undefined : Symbol(undefined)
@@ -0,0 +1,271 @@
=== tests/cases/conformance/types/members/typesWithVoidProperty.ts ===
interface X<T> {
done: true;
>done : true
>true : true
value: T;
>value : T
}
interface Y<T> {
done: true;
>done : true
>true : true
value?: T;
>value : T | undefined
}
declare let a: X<number>;
>a : X<number>
declare let b: X<void>;
>b : X<void>
declare let c: X<number | void>;
>c : X<number | void>
declare let d: Y<number>;
>d : Y<number>
a = b; // not allowed because `value` must be `number`
>a = b : X<void>
>a : X<number>
>b : X<void>
a = c; // not allowed because `value` must be `number`
>a = c : X<number | void>
>a : X<number>
>c : X<number | void>
a = d; // not allowed because `value` must be `number`
>a = d : Y<number>
>a : X<number>
>d : Y<number>
a = { done: true }; // not allowed because `value` is not optional (non-`void`)
>a = { done: true } : { done: true; }
>a : X<number>
>{ done: true } : { done: true; }
>done : true
>true : true
a = { done: true, value: 1 }; // allowed because `value` must be `number`
>a = { done: true, value: 1 } : { done: true; value: number; }
>a : X<number>
>{ done: true, value: 1 } : { done: true; value: number; }
>done : true
>true : true
>value : number
>1 : 1
a = { done: true, value: undefined }; // not allowed because `value` must be `number`
>a = { done: true, value: undefined } : { done: true; value: undefined; }
>a : X<number>
>{ done: true, value: undefined } : { done: true; value: undefined; }
>done : true
>true : true
>value : undefined
>undefined : undefined
a = { done: true, value: undefined as undefined }; // not allowed because `value` must be `number`
>a = { done: true, value: undefined as undefined } : { done: true; value: undefined; }
>a : X<number>
>{ done: true, value: undefined as undefined } : { done: true; value: undefined; }
>done : true
>true : true
>value : undefined
>undefined as undefined : undefined
>undefined : undefined
a = { done: true, value: undefined as void }; // not allowed because `value` must be `number`
>a = { done: true, value: undefined as void } : { done: true; value: void; }
>a : X<number>
>{ done: true, value: undefined as void } : { done: true; value: void; }
>done : true
>true : true
>value : void
>undefined as void : void
>undefined : undefined
b = a; // not allowed because `value` must be `void`
>b = a : X<number>
>b : X<void>
>a : X<number>
b = c; // not allowed because `value` must be `void`
>b = c : X<number | void>
>b : X<void>
>c : X<number | void>
b = d; // not allowed because `value` must be `void`
>b = d : Y<number>
>b : X<void>
>d : Y<number>
b = { done: true }; // allowed because `value` is optional due to `void`
>b = { done: true } : { done: true; }
>b : X<void>
>{ done: true } : { done: true; }
>done : true
>true : true
b = { done: true, value: 1 }; // not allowed because `value` must be `void`
>b = { done: true, value: 1 } : { done: true; value: number; }
>b : X<void>
>{ done: true, value: 1 } : { done: true; value: number; }
>done : true
>true : true
>value : number
>1 : 1
b = { done: true, value: undefined }; // allowed because `value` can be `undefined` (assignable to `void`)
>b = { done: true, value: undefined } : { done: true; value: undefined; }
>b : X<void>
>{ done: true, value: undefined } : { done: true; value: undefined; }
>done : true
>true : true
>value : undefined
>undefined : undefined
b = { done: true, value: undefined as undefined }; // allowed because `value` can be `undefined` (assignable to `void`)
>b = { done: true, value: undefined as undefined } : { done: true; value: undefined; }
>b : X<void>
>{ done: true, value: undefined as undefined } : { done: true; value: undefined; }
>done : true
>true : true
>value : undefined
>undefined as undefined : undefined
>undefined : undefined
b = { done: true, value: undefined as void }; // allowed because `value` must be `void`
>b = { done: true, value: undefined as void } : { done: true; value: void; }
>b : X<void>
>{ done: true, value: undefined as void } : { done: true; value: void; }
>done : true
>true : true
>value : void
>undefined as void : void
>undefined : undefined
c = a; // allowed because `value` can be `number`
>c = a : X<number>
>c : X<number | void>
>a : X<number>
c = b; // allowed because `value` can be `void`
>c = b : X<void>
>c : X<number | void>
>b : X<void>
c = d; // allowed because `value` can be `undefined`
>c = d : Y<number>
>c : X<number | void>
>d : Y<number>
c = { done: true }; // allowed because `value` is optional due to `void`
>c = { done: true } : { done: true; }
>c : X<number | void>
>{ done: true } : { done: true; }
>done : true
>true : true
c = { done: true, value: 1 }; // allowed because `value` can be `number`
>c = { done: true, value: 1 } : { done: true; value: number; }
>c : X<number | void>
>{ done: true, value: 1 } : { done: true; value: number; }
>done : true
>true : true
>value : number
>1 : 1
c = { done: true, value: undefined }; // allowed because `value` can be `undefined` (assignable to `void`)
>c = { done: true, value: undefined } : { done: true; value: undefined; }
>c : X<number | void>
>{ done: true, value: undefined } : { done: true; value: undefined; }
>done : true
>true : true
>value : undefined
>undefined : undefined
c = { done: true, value: undefined as undefined }; // allowed because `value` can be `undefined` (assignable to `void`)
>c = { done: true, value: undefined as undefined } : { done: true; value: undefined; }
>c : X<number | void>
>{ done: true, value: undefined as undefined } : { done: true; value: undefined; }
>done : true
>true : true
>value : undefined
>undefined as undefined : undefined
>undefined : undefined
c = { done: true, value: undefined as void }; // allowed because `value` can be `void`
>c = { done: true, value: undefined as void } : { done: true; value: void; }
>c : X<number | void>
>{ done: true, value: undefined as void } : { done: true; value: void; }
>done : true
>true : true
>value : void
>undefined as void : void
>undefined : undefined
d = a; // allowed because `value` must be `number | void`
>d = a : X<number>
>d : Y<number>
>a : X<number>
d = b; // not allowed because `value` must be `undefined`, and `void` is a supertype of `undefined`
>d = b : X<void>
>d : Y<number>
>b : X<void>
d = c; // not allowed allowed because `value` must be `undefined`, and `void` is a supertype of `undefined`
>d = c : X<number | void>
>d : Y<number>
>c : X<number | void>
d = { done: true }; // allowed because `value` is optional
>d = { done: true } : { done: true; }
>d : Y<number>
>{ done: true } : { done: true; }
>done : true
>true : true
d = { done: true, value: 1 }; // allowed because `value` can be `number`
>d = { done: true, value: 1 } : { done: true; value: number; }
>d : Y<number>
>{ done: true, value: 1 } : { done: true; value: number; }
>done : true
>true : true
>value : number
>1 : 1
d = { done: true, value: undefined }; // allowed because `value` can be `undefined`
>d = { done: true, value: undefined } : { done: true; value: undefined; }
>d : Y<number>
>{ done: true, value: undefined } : { done: true; value: undefined; }
>done : true
>true : true
>value : undefined
>undefined : undefined
d = { done: true, value: undefined as undefined }; // allowed because `value` can be `undefined`
>d = { done: true, value: undefined as undefined } : { done: true; value: undefined; }
>d : Y<number>
>{ done: true, value: undefined as undefined } : { done: true; value: undefined; }
>done : true
>true : true
>value : undefined
>undefined as undefined : undefined
>undefined : undefined
d = { done: true, value: undefined as void }; // not allowed because `value` can be `undefined`, and `void` is a supertype of `undefined
>d = { done: true, value: undefined as void } : { done: true; value: void; }
>d : Y<number>
>{ done: true, value: undefined as void } : { done: true; value: void; }
>done : true
>true : true
>value : void
>undefined as void : void
>undefined : undefined
@@ -88,9 +88,9 @@ i4 = i1; // Ok
i4 = i2; // Ok
i4 = i3; // Ok
interface Animal { animal: void }
interface Dog extends Animal { dog: void }
interface Cat extends Animal { cat: void }
interface Animal { animal: never }
interface Dog extends Animal { dog: never }
interface Cat extends Animal { cat: never }
interface Comparer1<T> {
compare(a: T, b: T): number;
@@ -6,7 +6,7 @@ export namespace dom {
[e: string]: {};
}
interface Element {
__domBrand: void;
__domBrand: never;
props: {
children?: Element[];
};
@@ -26,7 +26,7 @@ export namespace predom {
[e: string]: {};
}
interface Element {
__predomBrand: void;
__predomBrand: never;
props: {
children?: Element[];
};
@@ -46,7 +46,7 @@ import { predom } from "./renderer2"
export const MySFC = (props: {x: number, y: number, children?: predom.JSX.Element[]}) => <p>{props.x} + {props.y} = {props.x + props.y}{...this.props.children}</p>;
export class MyClass implements predom.JSX.Element {
__predomBrand!: void;
__predomBrand!: never;
constructor(public props: {x: number, y: number, children?: predom.JSX.Element[]}) {}
render() {
return <p>
@@ -69,7 +69,7 @@ elem = <h></h>; // Expect assignability error here
const DOMSFC = (props: {x: number, y: number, children?: dom.JSX.Element[]}) => <p>{props.x} + {props.y} = {props.x + props.y}{props.children}</p>;
class DOMClass implements dom.JSX.Element {
__domBrand!: void;
__domBrand!: never;
constructor(public props: {x: number, y: number, children?: dom.JSX.Element[]}) {}
render() {
return <p>{this.props.x} + {this.props.y} = {this.props.x + this.props.y}{...this.props.children}</p>;
@@ -6,7 +6,7 @@ declare global {
[e: string]: {};
}
interface Element {
__domBrand: void;
__domBrand: never;
children: Element[];
props: {};
}
@@ -22,7 +22,7 @@ export namespace predom {
[e: string]: {};
}
interface Element {
__predomBrand: void;
__predomBrand: never;
children: Element[];
props: {};
}
@@ -0,0 +1,53 @@
// @strict: true
// @noEmit: true
interface X<T> {
done: true;
value: T;
}
interface Y<T> {
done: true;
value?: T;
}
declare let a: X<number>;
declare let b: X<void>;
declare let c: X<number | void>;
declare let d: Y<number>;
a = b; // not allowed because `value` must be `number`
a = c; // not allowed because `value` must be `number`
a = d; // not allowed because `value` must be `number`
a = { done: true }; // not allowed because `value` is not optional (non-`void`)
a = { done: true, value: 1 }; // allowed because `value` must be `number`
a = { done: true, value: undefined }; // not allowed because `value` must be `number`
a = { done: true, value: undefined as undefined }; // not allowed because `value` must be `number`
a = { done: true, value: undefined as void }; // not allowed because `value` must be `number`
b = a; // not allowed because `value` must be `void`
b = c; // not allowed because `value` must be `void`
b = d; // not allowed because `value` must be `void`
b = { done: true }; // allowed because `value` is optional due to `void`
b = { done: true, value: 1 }; // not allowed because `value` must be `void`
b = { done: true, value: undefined }; // allowed because `value` can be `undefined` (assignable to `void`)
b = { done: true, value: undefined as undefined }; // allowed because `value` can be `undefined` (assignable to `void`)
b = { done: true, value: undefined as void }; // allowed because `value` must be `void`
c = a; // allowed because `value` can be `number`
c = b; // allowed because `value` can be `void`
c = d; // allowed because `value` can be `undefined`
c = { done: true }; // allowed because `value` is optional due to `void`
c = { done: true, value: 1 }; // allowed because `value` can be `number`
c = { done: true, value: undefined }; // allowed because `value` can be `undefined` (assignable to `void`)
c = { done: true, value: undefined as undefined }; // allowed because `value` can be `undefined` (assignable to `void`)
c = { done: true, value: undefined as void }; // allowed because `value` can be `void`
d = a; // allowed because `value` must be `number | void`
d = b; // not allowed because `value` must be `undefined`, and `void` is a supertype of `undefined`
d = c; // not allowed allowed because `value` must be `undefined`, and `void` is a supertype of `undefined`
d = { done: true }; // allowed because `value` is optional
d = { done: true, value: 1 }; // allowed because `value` can be `number`
d = { done: true, value: undefined }; // allowed because `value` can be `undefined`
d = { done: true, value: undefined as undefined }; // allowed because `value` can be `undefined`
d = { done: true, value: undefined as void }; // not allowed because `value` can be `undefined`, and `void` is a supertype of `undefined