From 37d539d92c114ebe50e0d74ae0e4b6c7b170c5d6 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 3 Mar 2020 12:19:14 -0800 Subject: [PATCH 1/6] Treat intersections of only objects as a single object in relations --- src/compiler/checker.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 18d32322297f0..bb3083144fe3b 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -15363,7 +15363,9 @@ namespace ts { // // - For a primitive type or type parameter (such as 'number = A & B') there is no point in // breaking the intersection apart. - result = someTypeRelatedToType(source, target, /*reportErrors*/ false, IntersectionState.Source); + if (!isNonGenericObjectType(target) || !every((source).types, isNonGenericObjectType)) { + result = someTypeRelatedToType(source, target, /*reportErrors*/ false, IntersectionState.Source); + } } if (!result && (source.flags & TypeFlags.StructuredOrInstantiable || target.flags & TypeFlags.StructuredOrInstantiable)) { if (result = recursiveTypeRelatedTo(source, target, reportErrors, intersectionState)) { From 583ca838db4b887e9b1365c371ea8e4c897c57f5 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 3 Mar 2020 14:08:24 -0800 Subject: [PATCH 2/6] Exclude intersections containing non-inferrable types --- src/compiler/checker.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index bb3083144fe3b..fe5d10949e7ff 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -15363,7 +15363,7 @@ namespace ts { // // - For a primitive type or type parameter (such as 'number = A & B') there is no point in // breaking the intersection apart. - if (!isNonGenericObjectType(target) || !every((source).types, isNonGenericObjectType)) { + if (!isNonGenericObjectType(target) || !every((source).types, t => isNonGenericObjectType(t) && !(getObjectFlags(t) & ObjectFlags.NonInferrableType))) { result = someTypeRelatedToType(source, target, /*reportErrors*/ false, IntersectionState.Source); } } From 1e114d2c5466c71067cb755ae8eb9d936e8b9add Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 3 Mar 2020 14:09:05 -0800 Subject: [PATCH 3/6] Accept new baselines --- ...ormalizedIntersectionTooComplex.errors.txt | 6 +- .../propTypeValidatorInference.errors.txt | 118 ++++++++++++++++++ 2 files changed, 121 insertions(+), 3 deletions(-) create mode 100644 tests/baselines/reference/propTypeValidatorInference.errors.txt diff --git a/tests/baselines/reference/normalizedIntersectionTooComplex.errors.txt b/tests/baselines/reference/normalizedIntersectionTooComplex.errors.txt index 64e7d7f00c510..4e214eff50715 100644 --- a/tests/baselines/reference/normalizedIntersectionTooComplex.errors.txt +++ b/tests/baselines/reference/normalizedIntersectionTooComplex.errors.txt @@ -1,5 +1,5 @@ +tests/cases/compiler/normalizedIntersectionTooComplex.ts(36,14): error TS2590: Expression produces a union type that is too complex to represent. tests/cases/compiler/normalizedIntersectionTooComplex.ts(36,40): error TS7006: Parameter 'x' implicitly has an 'any' type. -tests/cases/compiler/normalizedIntersectionTooComplex.ts(36,40): error TS2590: Expression produces a union type that is too complex to represent. ==== tests/cases/compiler/normalizedIntersectionTooComplex.ts (2 errors) ==== @@ -39,8 +39,8 @@ tests/cases/compiler/normalizedIntersectionTooComplex.ts(36,40): error TS2590: E declare var all: keyof Big; const ctor = getCtor(all); const comp = ctor({ common: "ok", ref: x => console.log(x) }); + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2590: Expression produces a union type that is too complex to represent. ~ !!! error TS7006: Parameter 'x' implicitly has an 'any' type. - ~~~~~~~~~~~~~~~~~~~ -!!! error TS2590: Expression produces a union type that is too complex to represent. \ No newline at end of file diff --git a/tests/baselines/reference/propTypeValidatorInference.errors.txt b/tests/baselines/reference/propTypeValidatorInference.errors.txt new file mode 100644 index 0000000000000..277ac5ce532ea --- /dev/null +++ b/tests/baselines/reference/propTypeValidatorInference.errors.txt @@ -0,0 +1,118 @@ +tests/cases/compiler/file.ts(35,5): error TS2322: Type 'Validator; bar: Requireable; baz: Requireable; }>>' is not assignable to type 'Validator<{ foo: string; bar?: boolean | undefined; baz?: any; }>'. + Type 'InferProps<{ foo: Validator; bar: Requireable; baz: Requireable; }>' is not assignable to type '{ foo: string; bar?: boolean | undefined; baz?: any; }'. + Types of property 'bar' are incompatible. + Type 'boolean | null | undefined' is not assignable to type 'boolean | undefined'. + Type 'null' is not assignable to type 'boolean | undefined'. +tests/cases/compiler/file.ts(36,5): error TS2322: Type 'Validator; bar: Validator; }>>' is not assignable to type 'Validator'. + Type 'string | boolean | InferProps<{ foo: Requireable; bar: Validator; }>' is not assignable to type 'string | boolean | { foo?: string | undefined; bar: number; }'. + Type 'InferProps<{ foo: Requireable; bar: Validator; }>' is not assignable to type 'string | boolean | { foo?: string | undefined; bar: number; }'. + Type 'InferProps<{ foo: Requireable; bar: Validator; }>' is not assignable to type '{ foo?: string | undefined; bar: number; }'. + Types of property 'foo' are incompatible. + Type 'string | null | undefined' is not assignable to type 'string | undefined'. + Type 'null' is not assignable to type 'string | undefined'. + + +==== tests/cases/compiler/node_modules/prop-types/index.d.ts (0 errors) ==== + export const nominalTypeHack: unique symbol; + + export type IsOptional = undefined | null extends T ? true : undefined extends T ? true : null extends T ? true : false; + + export type RequiredKeys = { [K in keyof V]-?: Exclude extends Validator ? IsOptional extends true ? never : K : never }[keyof V]; + export type OptionalKeys = Exclude>; + export type InferPropsInner = { [K in keyof V]-?: InferType; }; + + export interface Validator { + (props: object, propName: string, componentName: string, location: string, propFullName: string): Error | null; + [nominalTypeHack]?: T; + } + + export interface Requireable extends Validator { + isRequired: Validator>; + } + + export type ValidationMap = { [K in keyof T]?: Validator }; + + export type InferType = V extends Validator ? T : any; + export type InferProps = + & InferPropsInner>> + & Partial>>>; + + export const any: Requireable; + export const array: Requireable; + export const bool: Requireable; + export const string: Requireable; + export const number: Requireable; + export function shape

>(type: P): Requireable>; + export function oneOfType>(types: T[]): Requireable>>; + + +==== tests/cases/compiler/file.ts (2 errors) ==== + import * as PropTypes from "prop-types"; + interface Props { + any?: any; + array: string[]; + bool: boolean; + shape: { + foo: string; + bar?: boolean; + baz?: any + }; + oneOfType: string | boolean | { + foo?: string; + bar: number; + }; + } + + type PropTypesMap = PropTypes.ValidationMap; + + const innerProps = { + foo: PropTypes.string.isRequired, + bar: PropTypes.bool, + baz: PropTypes.any + }; + + const arrayOfTypes = [PropTypes.string, PropTypes.bool, PropTypes.shape({ + foo: PropTypes.string, + bar: PropTypes.number.isRequired + })]; + + // TS checking + const propTypes: PropTypesMap = { + any: PropTypes.any, + array: PropTypes.array.isRequired, + bool: PropTypes.bool.isRequired, + shape: PropTypes.shape(innerProps).isRequired, + ~~~~~ +!!! error TS2322: Type 'Validator; bar: Requireable; baz: Requireable; }>>' is not assignable to type 'Validator<{ foo: string; bar?: boolean | undefined; baz?: any; }>'. +!!! error TS2322: Type 'InferProps<{ foo: Validator; bar: Requireable; baz: Requireable; }>' is not assignable to type '{ foo: string; bar?: boolean | undefined; baz?: any; }'. +!!! error TS2322: Types of property 'bar' are incompatible. +!!! error TS2322: Type 'boolean | null | undefined' is not assignable to type 'boolean | undefined'. +!!! error TS2322: Type 'null' is not assignable to type 'boolean | undefined'. +!!! related TS6500 tests/cases/compiler/file.ts:6:5: The expected type comes from property 'shape' which is declared here on type 'ValidationMap' + oneOfType: PropTypes.oneOfType(arrayOfTypes).isRequired, + ~~~~~~~~~ +!!! error TS2322: Type 'Validator; bar: Validator; }>>' is not assignable to type 'Validator'. +!!! error TS2322: Type 'string | boolean | InferProps<{ foo: Requireable; bar: Validator; }>' is not assignable to type 'string | boolean | { foo?: string | undefined; bar: number; }'. +!!! error TS2322: Type 'InferProps<{ foo: Requireable; bar: Validator; }>' is not assignable to type 'string | boolean | { foo?: string | undefined; bar: number; }'. +!!! error TS2322: Type 'InferProps<{ foo: Requireable; bar: Validator; }>' is not assignable to type '{ foo?: string | undefined; bar: number; }'. +!!! error TS2322: Types of property 'foo' are incompatible. +!!! error TS2322: Type 'string | null | undefined' is not assignable to type 'string | undefined'. +!!! error TS2322: Type 'null' is not assignable to type 'string | undefined'. +!!! related TS6500 tests/cases/compiler/file.ts:11:5: The expected type comes from property 'oneOfType' which is declared here on type 'ValidationMap' + }; + + // JS checking + const propTypesWithoutAnnotation = { + any: PropTypes.any, + array: PropTypes.array.isRequired, + bool: PropTypes.bool.isRequired, + shape: PropTypes.shape(innerProps).isRequired, + oneOfType: PropTypes.oneOfType(arrayOfTypes).isRequired, + }; + + type ExtractedProps = PropTypes.InferProps; + + type ExtractedPropsWithoutAnnotation = PropTypes.InferProps; + + type ExtractPropsMatch = ExtractedProps extends ExtractedPropsWithoutAnnotation ? true : false; + const x: true = (null as any as ExtractPropsMatch); \ No newline at end of file From 0a207cc318a2d18aecdf5ba8decf76c2af39bfac Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 3 Mar 2020 14:10:32 -0800 Subject: [PATCH 4/6] Update test --- tests/cases/compiler/propTypeValidatorInference.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cases/compiler/propTypeValidatorInference.ts b/tests/cases/compiler/propTypeValidatorInference.ts index 54030ab91a916..9f6120a5d67ac 100644 --- a/tests/cases/compiler/propTypeValidatorInference.ts +++ b/tests/cases/compiler/propTypeValidatorInference.ts @@ -13,7 +13,7 @@ export interface Validator { [nominalTypeHack]?: T; } -export interface Requireable extends Validator { +export interface Requireable extends Validator { isRequired: Validator>; } From adeb53237bd61c794f5738f639135950a198d7a6 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 3 Mar 2020 14:10:40 -0800 Subject: [PATCH 5/6] Accept new baselines --- .../propTypeValidatorInference.errors.txt | 118 ------------------ .../reference/propTypeValidatorInference.js | 2 +- .../propTypeValidatorInference.symbols | 44 +++---- .../propTypeValidatorInference.types | 4 +- 4 files changed, 24 insertions(+), 144 deletions(-) delete mode 100644 tests/baselines/reference/propTypeValidatorInference.errors.txt diff --git a/tests/baselines/reference/propTypeValidatorInference.errors.txt b/tests/baselines/reference/propTypeValidatorInference.errors.txt deleted file mode 100644 index 277ac5ce532ea..0000000000000 --- a/tests/baselines/reference/propTypeValidatorInference.errors.txt +++ /dev/null @@ -1,118 +0,0 @@ -tests/cases/compiler/file.ts(35,5): error TS2322: Type 'Validator; bar: Requireable; baz: Requireable; }>>' is not assignable to type 'Validator<{ foo: string; bar?: boolean | undefined; baz?: any; }>'. - Type 'InferProps<{ foo: Validator; bar: Requireable; baz: Requireable; }>' is not assignable to type '{ foo: string; bar?: boolean | undefined; baz?: any; }'. - Types of property 'bar' are incompatible. - Type 'boolean | null | undefined' is not assignable to type 'boolean | undefined'. - Type 'null' is not assignable to type 'boolean | undefined'. -tests/cases/compiler/file.ts(36,5): error TS2322: Type 'Validator; bar: Validator; }>>' is not assignable to type 'Validator'. - Type 'string | boolean | InferProps<{ foo: Requireable; bar: Validator; }>' is not assignable to type 'string | boolean | { foo?: string | undefined; bar: number; }'. - Type 'InferProps<{ foo: Requireable; bar: Validator; }>' is not assignable to type 'string | boolean | { foo?: string | undefined; bar: number; }'. - Type 'InferProps<{ foo: Requireable; bar: Validator; }>' is not assignable to type '{ foo?: string | undefined; bar: number; }'. - Types of property 'foo' are incompatible. - Type 'string | null | undefined' is not assignable to type 'string | undefined'. - Type 'null' is not assignable to type 'string | undefined'. - - -==== tests/cases/compiler/node_modules/prop-types/index.d.ts (0 errors) ==== - export const nominalTypeHack: unique symbol; - - export type IsOptional = undefined | null extends T ? true : undefined extends T ? true : null extends T ? true : false; - - export type RequiredKeys = { [K in keyof V]-?: Exclude extends Validator ? IsOptional extends true ? never : K : never }[keyof V]; - export type OptionalKeys = Exclude>; - export type InferPropsInner = { [K in keyof V]-?: InferType; }; - - export interface Validator { - (props: object, propName: string, componentName: string, location: string, propFullName: string): Error | null; - [nominalTypeHack]?: T; - } - - export interface Requireable extends Validator { - isRequired: Validator>; - } - - export type ValidationMap = { [K in keyof T]?: Validator }; - - export type InferType = V extends Validator ? T : any; - export type InferProps = - & InferPropsInner>> - & Partial>>>; - - export const any: Requireable; - export const array: Requireable; - export const bool: Requireable; - export const string: Requireable; - export const number: Requireable; - export function shape

>(type: P): Requireable>; - export function oneOfType>(types: T[]): Requireable>>; - - -==== tests/cases/compiler/file.ts (2 errors) ==== - import * as PropTypes from "prop-types"; - interface Props { - any?: any; - array: string[]; - bool: boolean; - shape: { - foo: string; - bar?: boolean; - baz?: any - }; - oneOfType: string | boolean | { - foo?: string; - bar: number; - }; - } - - type PropTypesMap = PropTypes.ValidationMap; - - const innerProps = { - foo: PropTypes.string.isRequired, - bar: PropTypes.bool, - baz: PropTypes.any - }; - - const arrayOfTypes = [PropTypes.string, PropTypes.bool, PropTypes.shape({ - foo: PropTypes.string, - bar: PropTypes.number.isRequired - })]; - - // TS checking - const propTypes: PropTypesMap = { - any: PropTypes.any, - array: PropTypes.array.isRequired, - bool: PropTypes.bool.isRequired, - shape: PropTypes.shape(innerProps).isRequired, - ~~~~~ -!!! error TS2322: Type 'Validator; bar: Requireable; baz: Requireable; }>>' is not assignable to type 'Validator<{ foo: string; bar?: boolean | undefined; baz?: any; }>'. -!!! error TS2322: Type 'InferProps<{ foo: Validator; bar: Requireable; baz: Requireable; }>' is not assignable to type '{ foo: string; bar?: boolean | undefined; baz?: any; }'. -!!! error TS2322: Types of property 'bar' are incompatible. -!!! error TS2322: Type 'boolean | null | undefined' is not assignable to type 'boolean | undefined'. -!!! error TS2322: Type 'null' is not assignable to type 'boolean | undefined'. -!!! related TS6500 tests/cases/compiler/file.ts:6:5: The expected type comes from property 'shape' which is declared here on type 'ValidationMap' - oneOfType: PropTypes.oneOfType(arrayOfTypes).isRequired, - ~~~~~~~~~ -!!! error TS2322: Type 'Validator; bar: Validator; }>>' is not assignable to type 'Validator'. -!!! error TS2322: Type 'string | boolean | InferProps<{ foo: Requireable; bar: Validator; }>' is not assignable to type 'string | boolean | { foo?: string | undefined; bar: number; }'. -!!! error TS2322: Type 'InferProps<{ foo: Requireable; bar: Validator; }>' is not assignable to type 'string | boolean | { foo?: string | undefined; bar: number; }'. -!!! error TS2322: Type 'InferProps<{ foo: Requireable; bar: Validator; }>' is not assignable to type '{ foo?: string | undefined; bar: number; }'. -!!! error TS2322: Types of property 'foo' are incompatible. -!!! error TS2322: Type 'string | null | undefined' is not assignable to type 'string | undefined'. -!!! error TS2322: Type 'null' is not assignable to type 'string | undefined'. -!!! related TS6500 tests/cases/compiler/file.ts:11:5: The expected type comes from property 'oneOfType' which is declared here on type 'ValidationMap' - }; - - // JS checking - const propTypesWithoutAnnotation = { - any: PropTypes.any, - array: PropTypes.array.isRequired, - bool: PropTypes.bool.isRequired, - shape: PropTypes.shape(innerProps).isRequired, - oneOfType: PropTypes.oneOfType(arrayOfTypes).isRequired, - }; - - type ExtractedProps = PropTypes.InferProps; - - type ExtractedPropsWithoutAnnotation = PropTypes.InferProps; - - type ExtractPropsMatch = ExtractedProps extends ExtractedPropsWithoutAnnotation ? true : false; - const x: true = (null as any as ExtractPropsMatch); \ No newline at end of file diff --git a/tests/baselines/reference/propTypeValidatorInference.js b/tests/baselines/reference/propTypeValidatorInference.js index 3a6fa04fbe183..de1b7e99e1fc2 100644 --- a/tests/baselines/reference/propTypeValidatorInference.js +++ b/tests/baselines/reference/propTypeValidatorInference.js @@ -14,7 +14,7 @@ export interface Validator { [nominalTypeHack]?: T; } -export interface Requireable extends Validator { +export interface Requireable extends Validator { isRequired: Validator>; } diff --git a/tests/baselines/reference/propTypeValidatorInference.symbols b/tests/baselines/reference/propTypeValidatorInference.symbols index 32a4a3c1abf3b..320c2c46bcd25 100644 --- a/tests/baselines/reference/propTypeValidatorInference.symbols +++ b/tests/baselines/reference/propTypeValidatorInference.symbols @@ -59,14 +59,14 @@ export interface Validator { >T : Symbol(T, Decl(index.d.ts, 8, 27)) } -export interface Requireable extends Validator { +export interface Requireable extends Validator { >Requireable : Symbol(Requireable, Decl(index.d.ts, 11, 1)) >T : Symbol(T, Decl(index.d.ts, 13, 29)) >Validator : Symbol(Validator, Decl(index.d.ts, 6, 72)) >T : Symbol(T, Decl(index.d.ts, 13, 29)) isRequired: Validator>; ->isRequired : Symbol(Requireable.isRequired, Decl(index.d.ts, 13, 73)) +>isRequired : Symbol(Requireable.isRequired, Decl(index.d.ts, 13, 54)) >Validator : Symbol(Validator, Decl(index.d.ts, 6, 72)) >NonNullable : Symbol(NonNullable, Decl(lib.es5.d.ts, --, --)) >T : Symbol(T, Decl(index.d.ts, 13, 29)) @@ -202,11 +202,11 @@ const innerProps = { foo: PropTypes.string.isRequired, >foo : Symbol(foo, Decl(file.ts, 18, 20)) ->PropTypes.string.isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 73)) +>PropTypes.string.isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 54)) >PropTypes.string : Symbol(PropTypes.string, Decl(index.d.ts, 27, 12)) >PropTypes : Symbol(PropTypes, Decl(file.ts, 0, 6)) >string : Symbol(PropTypes.string, Decl(index.d.ts, 27, 12)) ->isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 73)) +>isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 54)) bar: PropTypes.bool, >bar : Symbol(bar, Decl(file.ts, 19, 37)) @@ -242,11 +242,11 @@ const arrayOfTypes = [PropTypes.string, PropTypes.bool, PropTypes.shape({ bar: PropTypes.number.isRequired >bar : Symbol(bar, Decl(file.ts, 25, 26)) ->PropTypes.number.isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 73)) +>PropTypes.number.isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 54)) >PropTypes.number : Symbol(PropTypes.number, Decl(index.d.ts, 28, 12)) >PropTypes : Symbol(PropTypes, Decl(file.ts, 0, 6)) >number : Symbol(PropTypes.number, Decl(index.d.ts, 28, 12)) ->isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 73)) +>isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 54)) })]; @@ -263,37 +263,37 @@ const propTypes: PropTypesMap = { array: PropTypes.array.isRequired, >array : Symbol(array, Decl(file.ts, 31, 23)) ->PropTypes.array.isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 73)) +>PropTypes.array.isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 54)) >PropTypes.array : Symbol(PropTypes.array, Decl(index.d.ts, 25, 12)) >PropTypes : Symbol(PropTypes, Decl(file.ts, 0, 6)) >array : Symbol(PropTypes.array, Decl(index.d.ts, 25, 12)) ->isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 73)) +>isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 54)) bool: PropTypes.bool.isRequired, >bool : Symbol(bool, Decl(file.ts, 32, 38)) ->PropTypes.bool.isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 73)) +>PropTypes.bool.isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 54)) >PropTypes.bool : Symbol(PropTypes.bool, Decl(index.d.ts, 26, 12)) >PropTypes : Symbol(PropTypes, Decl(file.ts, 0, 6)) >bool : Symbol(PropTypes.bool, Decl(index.d.ts, 26, 12)) ->isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 73)) +>isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 54)) shape: PropTypes.shape(innerProps).isRequired, >shape : Symbol(shape, Decl(file.ts, 33, 36)) ->PropTypes.shape(innerProps).isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 73)) +>PropTypes.shape(innerProps).isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 54)) >PropTypes.shape : Symbol(PropTypes.shape, Decl(index.d.ts, 28, 41)) >PropTypes : Symbol(PropTypes, Decl(file.ts, 0, 6)) >shape : Symbol(PropTypes.shape, Decl(index.d.ts, 28, 41)) >innerProps : Symbol(innerProps, Decl(file.ts, 18, 5)) ->isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 73)) +>isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 54)) oneOfType: PropTypes.oneOfType(arrayOfTypes).isRequired, >oneOfType : Symbol(oneOfType, Decl(file.ts, 34, 50)) ->PropTypes.oneOfType(arrayOfTypes).isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 73)) +>PropTypes.oneOfType(arrayOfTypes).isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 54)) >PropTypes.oneOfType : Symbol(PropTypes.oneOfType, Decl(index.d.ts, 29, 89)) >PropTypes : Symbol(PropTypes, Decl(file.ts, 0, 6)) >oneOfType : Symbol(PropTypes.oneOfType, Decl(index.d.ts, 29, 89)) >arrayOfTypes : Symbol(arrayOfTypes, Decl(file.ts, 24, 5)) ->isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 73)) +>isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 54)) }; @@ -309,37 +309,37 @@ const propTypesWithoutAnnotation = { array: PropTypes.array.isRequired, >array : Symbol(array, Decl(file.ts, 40, 23)) ->PropTypes.array.isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 73)) +>PropTypes.array.isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 54)) >PropTypes.array : Symbol(PropTypes.array, Decl(index.d.ts, 25, 12)) >PropTypes : Symbol(PropTypes, Decl(file.ts, 0, 6)) >array : Symbol(PropTypes.array, Decl(index.d.ts, 25, 12)) ->isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 73)) +>isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 54)) bool: PropTypes.bool.isRequired, >bool : Symbol(bool, Decl(file.ts, 41, 38)) ->PropTypes.bool.isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 73)) +>PropTypes.bool.isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 54)) >PropTypes.bool : Symbol(PropTypes.bool, Decl(index.d.ts, 26, 12)) >PropTypes : Symbol(PropTypes, Decl(file.ts, 0, 6)) >bool : Symbol(PropTypes.bool, Decl(index.d.ts, 26, 12)) ->isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 73)) +>isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 54)) shape: PropTypes.shape(innerProps).isRequired, >shape : Symbol(shape, Decl(file.ts, 42, 36)) ->PropTypes.shape(innerProps).isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 73)) +>PropTypes.shape(innerProps).isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 54)) >PropTypes.shape : Symbol(PropTypes.shape, Decl(index.d.ts, 28, 41)) >PropTypes : Symbol(PropTypes, Decl(file.ts, 0, 6)) >shape : Symbol(PropTypes.shape, Decl(index.d.ts, 28, 41)) >innerProps : Symbol(innerProps, Decl(file.ts, 18, 5)) ->isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 73)) +>isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 54)) oneOfType: PropTypes.oneOfType(arrayOfTypes).isRequired, >oneOfType : Symbol(oneOfType, Decl(file.ts, 43, 50)) ->PropTypes.oneOfType(arrayOfTypes).isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 73)) +>PropTypes.oneOfType(arrayOfTypes).isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 54)) >PropTypes.oneOfType : Symbol(PropTypes.oneOfType, Decl(index.d.ts, 29, 89)) >PropTypes : Symbol(PropTypes, Decl(file.ts, 0, 6)) >oneOfType : Symbol(PropTypes.oneOfType, Decl(index.d.ts, 29, 89)) >arrayOfTypes : Symbol(arrayOfTypes, Decl(file.ts, 24, 5)) ->isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 73)) +>isRequired : Symbol(PropTypes.Requireable.isRequired, Decl(index.d.ts, 13, 54)) }; diff --git a/tests/baselines/reference/propTypeValidatorInference.types b/tests/baselines/reference/propTypeValidatorInference.types index eb292dac5c486..5276e7837fbdd 100644 --- a/tests/baselines/reference/propTypeValidatorInference.types +++ b/tests/baselines/reference/propTypeValidatorInference.types @@ -35,9 +35,7 @@ export interface Validator { >nominalTypeHack : unique symbol } -export interface Requireable extends Validator { ->null : null - +export interface Requireable extends Validator { isRequired: Validator>; >isRequired : Validator> } From f902f8ac6cfcb0df41166109d83f26e0678092ac Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 3 Mar 2020 14:24:43 -0800 Subject: [PATCH 6/6] Add tests --- ...ersectionsAndOptionalProperties.errors.txt | 49 ++++++++++++++ .../intersectionsAndOptionalProperties.js | 33 ++++++++++ ...intersectionsAndOptionalProperties.symbols | 64 ++++++++++++++++++ .../intersectionsAndOptionalProperties.types | 65 +++++++++++++++++++ .../intersectionsAndOptionalProperties.ts | 23 +++++++ 5 files changed, 234 insertions(+) create mode 100644 tests/baselines/reference/intersectionsAndOptionalProperties.errors.txt create mode 100644 tests/baselines/reference/intersectionsAndOptionalProperties.js create mode 100644 tests/baselines/reference/intersectionsAndOptionalProperties.symbols create mode 100644 tests/baselines/reference/intersectionsAndOptionalProperties.types create mode 100644 tests/cases/compiler/intersectionsAndOptionalProperties.ts diff --git a/tests/baselines/reference/intersectionsAndOptionalProperties.errors.txt b/tests/baselines/reference/intersectionsAndOptionalProperties.errors.txt new file mode 100644 index 0000000000000..bcd0a6f841d88 --- /dev/null +++ b/tests/baselines/reference/intersectionsAndOptionalProperties.errors.txt @@ -0,0 +1,49 @@ +tests/cases/compiler/intersectionsAndOptionalProperties.ts(5,1): error TS2322: Type '{ a: null; b: string; }' is not assignable to type '{ a?: number | undefined; b: string; }'. + Types of property 'a' are incompatible. + Type 'null' is not assignable to type 'number | undefined'. +tests/cases/compiler/intersectionsAndOptionalProperties.ts(6,1): error TS2322: Type '{ a: null; } & { b: string; }' is not assignable to type '{ a?: number | undefined; b: string; }'. + Types of property 'a' are incompatible. + Type 'null' is not assignable to type 'number | undefined'. +tests/cases/compiler/intersectionsAndOptionalProperties.ts(19,5): error TS2322: Type 'From' is not assignable to type 'To'. + Types of property 'field' are incompatible. + Type 'null' is not assignable to type 'number | undefined'. +tests/cases/compiler/intersectionsAndOptionalProperties.ts(20,5): error TS2322: Type 'null' is not assignable to type 'number | undefined'. + + +==== tests/cases/compiler/intersectionsAndOptionalProperties.ts (4 errors) ==== + declare let x: { a?: number, b: string }; + declare let y: { a: null, b: string }; + declare let z: { a: null } & { b: string }; + + x = y; // Error + ~ +!!! error TS2322: Type '{ a: null; b: string; }' is not assignable to type '{ a?: number | undefined; b: string; }'. +!!! error TS2322: Types of property 'a' are incompatible. +!!! error TS2322: Type 'null' is not assignable to type 'number | undefined'. + x = z; // Error + ~ +!!! error TS2322: Type '{ a: null; } & { b: string; }' is not assignable to type '{ a?: number | undefined; b: string; }'. +!!! error TS2322: Types of property 'a' are incompatible. +!!! error TS2322: Type 'null' is not assignable to type 'number | undefined'. + + // Repro from #36604 + + interface To { + field?: number; + anotherField: string; + } + + type From = { field: null } & Omit; + + function foo(v: From) { + let x: To; + x = v; // Error + ~ +!!! error TS2322: Type 'From' is not assignable to type 'To'. +!!! error TS2322: Types of property 'field' are incompatible. +!!! error TS2322: Type 'null' is not assignable to type 'number | undefined'. + x.field = v.field; // Error + ~~~~~~~ +!!! error TS2322: Type 'null' is not assignable to type 'number | undefined'. + } + \ No newline at end of file diff --git a/tests/baselines/reference/intersectionsAndOptionalProperties.js b/tests/baselines/reference/intersectionsAndOptionalProperties.js new file mode 100644 index 0000000000000..b2f13a9f67955 --- /dev/null +++ b/tests/baselines/reference/intersectionsAndOptionalProperties.js @@ -0,0 +1,33 @@ +//// [intersectionsAndOptionalProperties.ts] +declare let x: { a?: number, b: string }; +declare let y: { a: null, b: string }; +declare let z: { a: null } & { b: string }; + +x = y; // Error +x = z; // Error + +// Repro from #36604 + +interface To { + field?: number; + anotherField: string; +} + +type From = { field: null } & Omit; + +function foo(v: From) { + let x: To; + x = v; // Error + x.field = v.field; // Error +} + + +//// [intersectionsAndOptionalProperties.js] +"use strict"; +x = y; // Error +x = z; // Error +function foo(v) { + var x; + x = v; // Error + x.field = v.field; // Error +} diff --git a/tests/baselines/reference/intersectionsAndOptionalProperties.symbols b/tests/baselines/reference/intersectionsAndOptionalProperties.symbols new file mode 100644 index 0000000000000..c5504794e6ea5 --- /dev/null +++ b/tests/baselines/reference/intersectionsAndOptionalProperties.symbols @@ -0,0 +1,64 @@ +=== tests/cases/compiler/intersectionsAndOptionalProperties.ts === +declare let x: { a?: number, b: string }; +>x : Symbol(x, Decl(intersectionsAndOptionalProperties.ts, 0, 11)) +>a : Symbol(a, Decl(intersectionsAndOptionalProperties.ts, 0, 16)) +>b : Symbol(b, Decl(intersectionsAndOptionalProperties.ts, 0, 28)) + +declare let y: { a: null, b: string }; +>y : Symbol(y, Decl(intersectionsAndOptionalProperties.ts, 1, 11)) +>a : Symbol(a, Decl(intersectionsAndOptionalProperties.ts, 1, 16)) +>b : Symbol(b, Decl(intersectionsAndOptionalProperties.ts, 1, 25)) + +declare let z: { a: null } & { b: string }; +>z : Symbol(z, Decl(intersectionsAndOptionalProperties.ts, 2, 11)) +>a : Symbol(a, Decl(intersectionsAndOptionalProperties.ts, 2, 16)) +>b : Symbol(b, Decl(intersectionsAndOptionalProperties.ts, 2, 30)) + +x = y; // Error +>x : Symbol(x, Decl(intersectionsAndOptionalProperties.ts, 0, 11)) +>y : Symbol(y, Decl(intersectionsAndOptionalProperties.ts, 1, 11)) + +x = z; // Error +>x : Symbol(x, Decl(intersectionsAndOptionalProperties.ts, 0, 11)) +>z : Symbol(z, Decl(intersectionsAndOptionalProperties.ts, 2, 11)) + +// Repro from #36604 + +interface To { +>To : Symbol(To, Decl(intersectionsAndOptionalProperties.ts, 5, 6)) + + field?: number; +>field : Symbol(To.field, Decl(intersectionsAndOptionalProperties.ts, 9, 14)) + + anotherField: string; +>anotherField : Symbol(To.anotherField, Decl(intersectionsAndOptionalProperties.ts, 10, 19)) +} + +type From = { field: null } & Omit; +>From : Symbol(From, Decl(intersectionsAndOptionalProperties.ts, 12, 1)) +>field : Symbol(field, Decl(intersectionsAndOptionalProperties.ts, 14, 14)) +>Omit : Symbol(Omit, Decl(lib.es5.d.ts, --, --)) +>To : Symbol(To, Decl(intersectionsAndOptionalProperties.ts, 5, 6)) + +function foo(v: From) { +>foo : Symbol(foo, Decl(intersectionsAndOptionalProperties.ts, 14, 49)) +>v : Symbol(v, Decl(intersectionsAndOptionalProperties.ts, 16, 13)) +>From : Symbol(From, Decl(intersectionsAndOptionalProperties.ts, 12, 1)) + + let x: To; +>x : Symbol(x, Decl(intersectionsAndOptionalProperties.ts, 17, 7)) +>To : Symbol(To, Decl(intersectionsAndOptionalProperties.ts, 5, 6)) + + x = v; // Error +>x : Symbol(x, Decl(intersectionsAndOptionalProperties.ts, 17, 7)) +>v : Symbol(v, Decl(intersectionsAndOptionalProperties.ts, 16, 13)) + + x.field = v.field; // Error +>x.field : Symbol(To.field, Decl(intersectionsAndOptionalProperties.ts, 9, 14)) +>x : Symbol(x, Decl(intersectionsAndOptionalProperties.ts, 17, 7)) +>field : Symbol(To.field, Decl(intersectionsAndOptionalProperties.ts, 9, 14)) +>v.field : Symbol(field, Decl(intersectionsAndOptionalProperties.ts, 14, 14)) +>v : Symbol(v, Decl(intersectionsAndOptionalProperties.ts, 16, 13)) +>field : Symbol(field, Decl(intersectionsAndOptionalProperties.ts, 14, 14)) +} + diff --git a/tests/baselines/reference/intersectionsAndOptionalProperties.types b/tests/baselines/reference/intersectionsAndOptionalProperties.types new file mode 100644 index 0000000000000..7f5af60c18e6f --- /dev/null +++ b/tests/baselines/reference/intersectionsAndOptionalProperties.types @@ -0,0 +1,65 @@ +=== tests/cases/compiler/intersectionsAndOptionalProperties.ts === +declare let x: { a?: number, b: string }; +>x : { a?: number | undefined; b: string; } +>a : number | undefined +>b : string + +declare let y: { a: null, b: string }; +>y : { a: null; b: string; } +>a : null +>null : null +>b : string + +declare let z: { a: null } & { b: string }; +>z : { a: null; } & { b: string; } +>a : null +>null : null +>b : string + +x = y; // Error +>x = y : { a: null; b: string; } +>x : { a?: number | undefined; b: string; } +>y : { a: null; b: string; } + +x = z; // Error +>x = z : { a: null; } & { b: string; } +>x : { a?: number | undefined; b: string; } +>z : { a: null; } & { b: string; } + +// Repro from #36604 + +interface To { + field?: number; +>field : number | undefined + + anotherField: string; +>anotherField : string +} + +type From = { field: null } & Omit; +>From : From +>field : null +>null : null + +function foo(v: From) { +>foo : (v: From) => void +>v : From + + let x: To; +>x : To + + x = v; // Error +>x = v : From +>x : To +>v : From + + x.field = v.field; // Error +>x.field = v.field : null +>x.field : number | undefined +>x : To +>field : number | undefined +>v.field : null +>v : From +>field : null +} + diff --git a/tests/cases/compiler/intersectionsAndOptionalProperties.ts b/tests/cases/compiler/intersectionsAndOptionalProperties.ts new file mode 100644 index 0000000000000..a5bc4a1580af4 --- /dev/null +++ b/tests/cases/compiler/intersectionsAndOptionalProperties.ts @@ -0,0 +1,23 @@ +// @strict: true + +declare let x: { a?: number, b: string }; +declare let y: { a: null, b: string }; +declare let z: { a: null } & { b: string }; + +x = y; // Error +x = z; // Error + +// Repro from #36604 + +interface To { + field?: number; + anotherField: string; +} + +type From = { field: null } & Omit; + +function foo(v: From) { + let x: To; + x = v; // Error + x.field = v.field; // Error +}