Compare commits

...

14 commits

Author SHA1 Message Date
Nathan Shively-Sanders a47fb274ad Merge branch 'master' into difference-type-WIP 2017-01-10 13:28:38 -08:00
Nathan Shively-Sanders 55d8dcfc3d Add more difference type assignability tests 2017-01-10 13:15:11 -08:00
Nathan Shively-Sanders 813e2352dc Add difference type error tests and update baselines 2017-01-10 11:36:47 -08:00
Nathan Shively-Sanders bd24964b9c Check difference type nodes
Clean up getDifferenceType a bit as well
2017-01-10 11:36:06 -08:00
Nathan Shively-Sanders fd368284c6 Add a few difference test cases and update baselines 2017-01-10 08:26:01 -08:00
Nathan Shively-Sanders 330ea37603 Difference type cleanup
1. Improve assignability code (much cleaner now).
2. Add declaration emit.
3. Add stub for checkDifferenceTypeNode
2017-01-10 08:24:40 -08:00
Nathan Shively-Sanders 24c5d86902 Update baselines
And add a few more difference type assignability cases
2017-01-09 13:38:09 -08:00
Nathan Shively-Sanders d8b25a4371 Add and update difference type tests 2017-01-06 16:00:24 -08:00
Nathan Shively-Sanders f9ec6aa296 First draft of difference type assignability.
It mostly works, but is badly written.
2017-01-06 15:59:36 -08:00
Nathan Shively-Sanders 2119d59a11 Rest of difference type except assignability and grammar checks 2017-01-06 14:24:02 -08:00
Nathan Shively-Sanders d935cdbad1 Add some difference type tests
The generic test doesn't pass yet
2017-01-06 10:26:03 -08:00
Nathan Shively-Sanders 6897baaba2 Create instantiated difference types 2017-01-06 10:24:37 -08:00
Nathan Shively-Sanders f11b07f976 Move parseDifferenceType and change its precedence 2017-01-04 15:52:56 -08:00
Nathan Shively-Sanders 8eb9e93b48 Add difference types, and parse them 2017-01-04 15:32:05 -08:00
17 changed files with 807 additions and 9 deletions

View file

@ -124,6 +124,7 @@ namespace ts {
const tupleTypes: GenericType[] = [];
const unionTypes = createMap<UnionType>();
const intersectionTypes = createMap<IntersectionType>();
const differenceTypes = createMap<DifferenceType>();
const stringLiteralTypes = createMap<LiteralType>();
const numericLiteralTypes = createMap<LiteralType>();
const indexedAccessTypes = createMap<IndexedAccessType>();
@ -2321,6 +2322,9 @@ namespace ts {
else if (type.flags & TypeFlags.UnionOrIntersection) {
writeUnionOrIntersectionType(<UnionOrIntersectionType>type, nextFlags);
}
else if (type.flags & TypeFlags.Difference) {
writeDifferenceType(type as DifferenceType, nextFlags);
}
else if (getObjectFlags(type) & (ObjectFlags.Anonymous | ObjectFlags.Mapped)) {
writeAnonymousType(<ObjectType>type, nextFlags);
}
@ -2436,6 +2440,16 @@ namespace ts {
}
}
function writeDifferenceType(type: DifferenceType, flags: TypeFormatFlags) {
if (flags & TypeFormatFlags.InElementType) {
writePunctuation(writer, SyntaxKind.OpenParenToken);
}
writeTypeList([type.source, type.remove], SyntaxKind.MinusToken);
if (flags & TypeFormatFlags.InElementType) {
writePunctuation(writer, SyntaxKind.CloseParenToken);
}
}
function writeAnonymousType(type: ObjectType, flags: TypeFormatFlags) {
const symbol = type.symbol;
if (symbol) {
@ -4828,13 +4842,18 @@ namespace ts {
}
}
function getApparentTypeOfDifference(type: DifferenceType) {
return getDifferenceType(getApparentType(type.source), getApparentType(type.remove));
}
/**
* For a type parameter, return the base constraint of the type parameter. For the string, number,
* boolean, and symbol primitive types, return the corresponding object types. Otherwise return the
* type itself. Note that the apparent type of a union type is the union type itself.
*/
function getApparentType(type: Type): Type {
const t = type.flags & TypeFlags.TypeVariable ? getBaseConstraintOfTypeVariable(<TypeVariable>type) || emptyObjectType : type;
const t = type.flags & TypeFlags.TypeVariable ? getBaseConstraintOfTypeVariable(<TypeVariable>type) || emptyObjectType :
type.flags & TypeFlags.Difference ? getApparentTypeOfDifference(type as DifferenceType) : type;
return t.flags & TypeFlags.StringLike ? globalStringType :
t.flags & TypeFlags.NumberLike ? globalNumberType :
t.flags & TypeFlags.BooleanLike ? globalBooleanType :
@ -6028,6 +6047,54 @@ namespace ts {
return links.resolvedType;
}
function getTypeFromDifferenceTypeNode(node: DifferenceTypeNode): Type {
const links = getNodeLinks(node);
if (!links.resolvedType) {
links.resolvedType = getDifferenceType(getTypeFromTypeNode(node.source), getTypeFromTypeNode(node.remove));
}
return links.resolvedType;
}
function getDifferenceType(source: Type, remove: Type) {
//TOOD: Handle any here (if source is any, the result is any; if remove is any, the result is never. or any?!)
if (source.flags & TypeFlags.Any || remove.flags & TypeFlags.Any) {
return anyType;
}
const id = getTypeListId([source, remove]);
if (id in differenceTypes) {
return differenceTypes[id];
}
// TODO: Simplifications first (intersection distributes over difference)
// if left and right are both string literal union, then return the removal of right's contents from left's
// TODO: Probably should delay or paper over this check, but whatever. I'll write it for now.
if (isStringLiteralUnion(source) && remove.flags & TypeFlags.StringLiteral) {
return filterType(source, t => t !== remove);
}
if (isStringLiteralUnion(source) && isStringLiteralUnion(remove)) {
return filterType(source, t => (remove as UnionType).types.indexOf(t) === -1);
}
// if either left or right is a type parameter, then return a difference type
// TODO: Add tests with keyof T
if (source.flags & (TypeFlags.TypeParameter | TypeFlags.Index) || remove.flags & (TypeFlags.TypeParameter | TypeFlags.Index)) {
const difference = differenceTypes[id] = createType(TypeFlags.Difference) as DifferenceType;
difference.source = source;
difference.remove = remove;
return difference;
}
// if right is string then return never
if ((source.flags & TypeFlags.StringLike || isStringLiteralUnion(source)) && remove.flags & TypeFlags.String) {
return neverType;
}
// otherwise just return source
return source;
}
function isStringLiteralUnion(type: Type) {
return type.flags & TypeFlags.StringLiteral ||
type.flags & TypeFlags.Union && every((type as UnionType).types, t => !!(t.flags & TypeFlags.StringLiteral));
}
function getIndexTypeForGenericType(type: TypeVariable | UnionOrIntersectionType) {
if (!type.resolvedIndexType) {
type.resolvedIndexType = <IndexType>createType(TypeFlags.Index);
@ -6444,6 +6511,8 @@ namespace ts {
case SyntaxKind.UnionType:
case SyntaxKind.JSDocUnionType:
return getTypeFromUnionTypeNode(<UnionTypeNode>node);
case SyntaxKind.DifferenceType:
return getTypeFromDifferenceTypeNode(node as DifferenceTypeNode);
case SyntaxKind.IntersectionType:
return getTypeFromIntersectionTypeNode(<IntersectionTypeNode>node);
case SyntaxKind.ParenthesizedType:
@ -6821,6 +6890,10 @@ namespace ts {
if (type.flags & TypeFlags.Intersection) {
return getIntersectionType(instantiateTypes((<IntersectionType>type).types, mapper), type.aliasSymbol, instantiateTypes(type.aliasTypeArguments, mapper));
}
if (type.flags & TypeFlags.Difference) {
const difference = type as DifferenceType;
return getDifferenceType(instantiateType(difference.source, mapper), instantiateType(difference.remove, mapper));
}
if (type.flags & TypeFlags.Index) {
return getIndexType(instantiateType((<IndexType>type).type, mapper));
}
@ -7456,6 +7529,21 @@ namespace ts {
}
}
}
else if (target.flags & TypeFlags.Difference) {
if (source.flags & TypeFlags.TypeParameter && (target as DifferenceType).source === source) {
return Ternary.True;
}
else if (source.flags & TypeFlags.Difference) {
const srcDiff = source as DifferenceType;
const tgtDiff = target as DifferenceType;
if ((result = isRelatedTo(srcDiff.source, tgtDiff.source, reportErrors)) === Ternary.False) {
return result;
}
if (result = isRelatedTo(srcDiff.remove, tgtDiff.remove, reportErrors)) {
return result;
}
}
}
if (source.flags & TypeFlags.TypeParameter) {
// A source type T is related to a target type { [P in keyof T]: X } if T[P] is related to X.
@ -16039,6 +16127,21 @@ namespace ts {
forEach(node.types, checkSourceElement);
}
function checkDifferenceType(node: DifferenceTypeNode) {
const remove = getTypeFromTypeNode(node.remove);
if (!(remove.flags & (TypeFlags.Index | TypeFlags.TypeParameter | TypeFlags.String) || isStringLiteralUnion(remove))) {
error(node.remove, Diagnostics.The_right_side_of_a_difference_type_must_be_a_string_or_string_literal_union_or_a_type_parameter_constrained_to_one_of_these);
}
if (remove.flags & TypeFlags.TypeParameter) {
const constraint = (remove as TypeParameter).constraint;
if (constraint && !(constraint.flags & (TypeFlags.Index | TypeFlags.String) || isStringLiteralUnion(constraint))) {
error(node.remove, Diagnostics.The_right_side_of_a_difference_type_must_be_a_string_or_string_literal_union_or_a_type_parameter_constrained_to_one_of_these);
}
}
checkSourceElement(node.source);
checkSourceElement(node.remove);
}
function checkIndexedAccessIndexType(type: Type, accessNode: ElementAccessExpression | IndexedAccessTypeNode) {
if (type.flags & TypeFlags.IndexedAccess) {
// Check that the index type is assignable to 'keyof T' for the object type.
@ -19378,6 +19481,8 @@ namespace ts {
case SyntaxKind.UnionType:
case SyntaxKind.IntersectionType:
return checkUnionOrIntersectionType(<UnionOrIntersectionTypeNode>node);
case SyntaxKind.DifferenceType:
return checkDifferenceType(node as DifferenceTypeNode);
case SyntaxKind.ParenthesizedType:
case SyntaxKind.TypeOperator:
return checkSourceElement((<ParenthesizedTypeNode | TypeOperatorNode>node).type);

View file

@ -1174,6 +1174,13 @@ namespace ts {
writeLine();
}
function emitDifferenceType(node: DifferenceTypeNode) {
emitType(node.source);
write("-");
emitType(node.remove);
writeLine();
}
function emitVariableDeclaration(node: VariableDeclaration | PropertyDeclaration | PropertySignature | ParameterDeclaration) {
// If we are emitting property it isn't moduleElement and hence we already know it needs to be emitted
// so there is no check needed to see if declaration is visible
@ -1761,6 +1768,8 @@ namespace ts {
case SyntaxKind.GetAccessor:
case SyntaxKind.SetAccessor:
return emitAccessorDeclaration(<AccessorDeclaration>node);
case SyntaxKind.DifferenceType:
return emitDifferenceType(node as DifferenceTypeNode);
case SyntaxKind.PropertyDeclaration:
case SyntaxKind.PropertySignature:
return emitPropertyDeclaration(<PropertyDeclaration>node);

View file

@ -2035,6 +2035,10 @@
"category": "Error",
"code": 2704
},
"The right side of a difference type must be a string or string literal union, or a type parameter constrained to one of these.": {
"category": "Error",
"code": 2705
},
"Import declaration '{0}' is using private name '{1}'.": {
"category": "Error",

View file

@ -135,6 +135,9 @@ namespace ts {
case SyntaxKind.UnionType:
case SyntaxKind.IntersectionType:
return visitNodes(cbNodes, (<UnionOrIntersectionTypeNode>node).types);
case SyntaxKind.DifferenceType:
return visitNode(cbNode, (node as DifferenceTypeNode).source) ||
visitNode(cbNode, (node as DifferenceTypeNode).remove);
case SyntaxKind.ParenthesizedType:
case SyntaxKind.TypeOperator:
return visitNode(cbNode, (<ParenthesizedTypeNode | TypeOperatorNode>node).type);
@ -2639,7 +2642,25 @@ namespace ts {
return type;
}
function parseIntersectionTypeOrHigher(): TypeNode {
function parseDifferenceTypeOrHigher(): TypeNode {
let source = parseUnionTypeOrHigher();
// create left-associative difference types as long as the parser sees `-`
while (token() === SyntaxKind.MinusToken) {
parseTokenNode();
// not sure which parsing function to call here maybe just parseType? Or parseTypeOperatorOrHigher?
source = makeDifferenceType(source, parseType());
}
return source;
}
function makeDifferenceType(source: TypeNode, remove: TypeNode) {
const node = createNode(SyntaxKind.DifferenceType, source.pos) as DifferenceTypeNode;
node.source = source;
node.remove = remove;
return finishNode(node);
}
function parseIntersectionTypeOrHigher(): TypeNode {
return parseUnionOrIntersectionType(SyntaxKind.IntersectionType, parseTypeOperatorOrHigher, SyntaxKind.AmpersandToken);
}
@ -2736,7 +2757,7 @@ namespace ts {
if (token() === SyntaxKind.NewKeyword) {
return parseFunctionOrConstructorType(SyntaxKind.ConstructorType);
}
return parseUnionTypeOrHigher();
return parseDifferenceTypeOrHigher();
}
function parseTypeAnnotation(): TypeNode {

View file

@ -216,6 +216,7 @@ namespace ts {
TupleType,
UnionType,
IntersectionType,
DifferenceType,
ParenthesizedType,
ThisType,
TypeOperator,
@ -886,6 +887,12 @@ namespace ts {
kind: SyntaxKind.IntersectionType;
}
export interface DifferenceTypeNode extends TypeNode {
kind: SyntaxKind.DifferenceType;
source: TypeNode;
remove: TypeNode;
}
export interface ParenthesizedTypeNode extends TypeNode {
kind: SyntaxKind.ParenthesizedType;
type: TypeNode;
@ -2788,6 +2795,7 @@ namespace ts {
/* @internal */
ContainsAnyFunctionType = 1 << 23, // Type is or contains object literal type
NonPrimitive = 1 << 24, // intrinsic object type
Difference = 1 << 25, // (keyof T - keyof U)
/* @internal */
Nullable = Undefined | Null,
@ -2932,6 +2940,11 @@ namespace ts {
export type StructuredType = ObjectType | UnionType | IntersectionType;
export interface DifferenceType extends Type {
source: Type; // both should be index type (keyof T), string or string literal union
remove: Type; // or a type parameter constrained to one of those 3 types
}
/* @internal */
// An instantiated anonymous type has a target and a mapper
export interface AnonymousType extends ObjectType {

View file

@ -0,0 +1,47 @@
//// [differenceType.ts]
type A = 'a';
type B = 'b';
type C = 'c';
type AB = A | B;
let nothing: A - 'a';
let none: AB - 'a' | 'b';
let over: 'a' - 'a' | 'b';
let under: 'a' | 'b' - 'a';
let partial: 'a' | 'b' - 'b' | 'd';
let empty: AB - AB;
let nope: string - string;
let nope2: 'a' | 'b' - string;
let nope3: string - 'a' | 'b';
type Abcd = { a; b; c; d }
function f<T,U extends keyof Abcd> (t: T, u: U) {
let usubtkey: U - keyof T;
let usubukey: U - keyof U;
usubtkey = usubtkey;
let tsubu: T - U;
return tsubu;
}
const x = f<'a' | 'b', 'b' | 'd'>('a', 'b');
//// [differenceType.js]
var nothing;
var none;
var over;
var under;
var partial;
var empty;
var nope;
var nope2;
var nope3;
function f(t, u) {
var usubtkey;
var usubukey;
usubtkey = usubtkey;
var tsubu;
return tsubu;
}
var x = f('a', 'b');

View file

@ -0,0 +1,90 @@
=== tests/cases/conformance/types/rest/differenceType.ts ===
type A = 'a';
>A : Symbol(A, Decl(differenceType.ts, 0, 0))
type B = 'b';
>B : Symbol(B, Decl(differenceType.ts, 0, 13))
type C = 'c';
>C : Symbol(C, Decl(differenceType.ts, 1, 13))
type AB = A | B;
>AB : Symbol(AB, Decl(differenceType.ts, 2, 13))
>A : Symbol(A, Decl(differenceType.ts, 0, 0))
>B : Symbol(B, Decl(differenceType.ts, 0, 13))
let nothing: A - 'a';
>nothing : Symbol(nothing, Decl(differenceType.ts, 4, 3))
>A : Symbol(A, Decl(differenceType.ts, 0, 0))
let none: AB - 'a' | 'b';
>none : Symbol(none, Decl(differenceType.ts, 5, 3))
>AB : Symbol(AB, Decl(differenceType.ts, 2, 13))
let over: 'a' - 'a' | 'b';
>over : Symbol(over, Decl(differenceType.ts, 6, 3))
let under: 'a' | 'b' - 'a';
>under : Symbol(under, Decl(differenceType.ts, 7, 3))
let partial: 'a' | 'b' - 'b' | 'd';
>partial : Symbol(partial, Decl(differenceType.ts, 8, 3))
let empty: AB - AB;
>empty : Symbol(empty, Decl(differenceType.ts, 9, 3))
>AB : Symbol(AB, Decl(differenceType.ts, 2, 13))
>AB : Symbol(AB, Decl(differenceType.ts, 2, 13))
let nope: string - string;
>nope : Symbol(nope, Decl(differenceType.ts, 10, 3))
let nope2: 'a' | 'b' - string;
>nope2 : Symbol(nope2, Decl(differenceType.ts, 11, 3))
let nope3: string - 'a' | 'b';
>nope3 : Symbol(nope3, Decl(differenceType.ts, 12, 3))
type Abcd = { a; b; c; d }
>Abcd : Symbol(Abcd, Decl(differenceType.ts, 12, 30))
>a : Symbol(a, Decl(differenceType.ts, 14, 13))
>b : Symbol(b, Decl(differenceType.ts, 14, 16))
>c : Symbol(c, Decl(differenceType.ts, 14, 19))
>d : Symbol(d, Decl(differenceType.ts, 14, 22))
function f<T,U extends keyof Abcd> (t: T, u: U) {
>f : Symbol(f, Decl(differenceType.ts, 14, 26))
>T : Symbol(T, Decl(differenceType.ts, 16, 11))
>U : Symbol(U, Decl(differenceType.ts, 16, 13))
>Abcd : Symbol(Abcd, Decl(differenceType.ts, 12, 30))
>t : Symbol(t, Decl(differenceType.ts, 16, 36))
>T : Symbol(T, Decl(differenceType.ts, 16, 11))
>u : Symbol(u, Decl(differenceType.ts, 16, 41))
>U : Symbol(U, Decl(differenceType.ts, 16, 13))
let usubtkey: U - keyof T;
>usubtkey : Symbol(usubtkey, Decl(differenceType.ts, 17, 7))
>U : Symbol(U, Decl(differenceType.ts, 16, 13))
>T : Symbol(T, Decl(differenceType.ts, 16, 11))
let usubukey: U - keyof U;
>usubukey : Symbol(usubukey, Decl(differenceType.ts, 18, 7))
>U : Symbol(U, Decl(differenceType.ts, 16, 13))
>U : Symbol(U, Decl(differenceType.ts, 16, 13))
usubtkey = usubtkey;
>usubtkey : Symbol(usubtkey, Decl(differenceType.ts, 17, 7))
>usubtkey : Symbol(usubtkey, Decl(differenceType.ts, 17, 7))
let tsubu: T - U;
>tsubu : Symbol(tsubu, Decl(differenceType.ts, 21, 7))
>T : Symbol(T, Decl(differenceType.ts, 16, 11))
>U : Symbol(U, Decl(differenceType.ts, 16, 13))
return tsubu;
>tsubu : Symbol(tsubu, Decl(differenceType.ts, 21, 7))
}
const x = f<'a' | 'b', 'b' | 'd'>('a', 'b');
>x : Symbol(x, Decl(differenceType.ts, 25, 5))
>f : Symbol(f, Decl(differenceType.ts, 14, 26))

View file

@ -0,0 +1,94 @@
=== tests/cases/conformance/types/rest/differenceType.ts ===
type A = 'a';
>A : "a"
type B = 'b';
>B : "b"
type C = 'c';
>C : "c"
type AB = A | B;
>AB : "a" | "b"
>A : "a"
>B : "b"
let nothing: A - 'a';
>nothing : never
>A : "a"
let none: AB - 'a' | 'b';
>none : never
>AB : "a" | "b"
let over: 'a' - 'a' | 'b';
>over : never
let under: 'a' | 'b' - 'a';
>under : "b"
let partial: 'a' | 'b' - 'b' | 'd';
>partial : "a"
let empty: AB - AB;
>empty : never
>AB : "a" | "b"
>AB : "a" | "b"
let nope: string - string;
>nope : never
let nope2: 'a' | 'b' - string;
>nope2 : never
let nope3: string - 'a' | 'b';
>nope3 : string
type Abcd = { a; b; c; d }
>Abcd : Abcd
>a : any
>b : any
>c : any
>d : any
function f<T,U extends keyof Abcd> (t: T, u: U) {
>f : <T, U extends "a" | "b" | "d" | "c">(t: T, u: U) => T - U
>T : T
>U : U
>Abcd : Abcd
>t : T
>T : T
>u : U
>U : U
let usubtkey: U - keyof T;
>usubtkey : U - keyof T
>U : U
>T : T
let usubukey: U - keyof U;
>usubukey : U - keyof U
>U : U
>U : U
usubtkey = usubtkey;
>usubtkey = usubtkey : U - keyof T
>usubtkey : U - keyof T
>usubtkey : U - keyof T
let tsubu: T - U;
>tsubu : T - U
>T : T
>U : U
return tsubu;
>tsubu : T - U
}
const x = f<'a' | 'b', 'b' | 'd'>('a', 'b');
>x : "a"
>f<'a' | 'b', 'b' | 'd'>('a', 'b') : "a"
>f : <T, U extends "a" | "b" | "d" | "c">(t: T, u: U) => T - U
>'a' : "a"
>'b' : "b"

View file

@ -0,0 +1,125 @@
tests/cases/conformance/types/rest/differenceTypeAssignability.ts(14,5): error TS2322: Type 'T - V' is not assignable to type 'T - U'.
Type 'V' is not assignable to type 'U'.
Type 'string' is not assignable to type 'U'.
tests/cases/conformance/types/rest/differenceTypeAssignability.ts(15,5): error TS2322: Type 'U' is not assignable to type 'T'.
Type '"u"' is not assignable to type 'T'.
tests/cases/conformance/types/rest/differenceTypeAssignability.ts(26,5): error TS2322: Type 'T - "c"' is not assignable to type 'T - "a"'.
Type '"c"' is not assignable to type '"a"'.
tests/cases/conformance/types/rest/differenceTypeAssignability.ts(27,5): error TS2322: Type 'T - AB' is not assignable to type 'T - "a"'.
Type 'AB' is not assignable to type '"a"'.
Type '"b"' is not assignable to type '"a"'.
tests/cases/conformance/types/rest/differenceTypeAssignability.ts(28,5): error TS2322: Type 'T - "a"' is not assignable to type 'T'.
tests/cases/conformance/types/rest/differenceTypeAssignability.ts(29,5): error TS2322: Type 'U' is not assignable to type 'T'.
Type '"u"' is not assignable to type 'T'.
tests/cases/conformance/types/rest/differenceTypeAssignability.ts(38,5): error TS2322: Type '{ a: any; }' is not assignable to type '{ a: any; b: any; }'.
Property 'b' is missing in type '{ a: any; }'.
tests/cases/conformance/types/rest/differenceTypeAssignability.ts(39,5): error TS2322: Type '{ a: any; b: any; } - T' is not assignable to type '{ a: any; b: any; } - U'.
Type 'T' is not assignable to type 'U'.
Type '"x" | "y" | "z"' is not assignable to type 'U'.
Type '"x"' is not assignable to type 'U'.
tests/cases/conformance/types/rest/differenceTypeAssignability.ts(40,5): error TS2322: Type '{ a: any; c: any; }' is not assignable to type '{ a: any; b: any; }'.
Property 'b' is missing in type '{ a: any; c: any; }'.
tests/cases/conformance/types/rest/differenceTypeAssignability.ts(42,5): error TS2322: Type '{ a: any; }' is not assignable to type 'T'.
tests/cases/conformance/types/rest/differenceTypeAssignability.ts(43,5): error TS2322: Type 'T - U' is not assignable to type 'T - "a"'.
Type 'U' is not assignable to type '"a"'.
Type '"u"' is not assignable to type '"a"'.
tests/cases/conformance/types/rest/differenceTypeAssignability.ts(44,5): error TS2322: Type 'T - "a"' is not assignable to type 'T - U'.
Type '"a"' is not assignable to type 'U'.
tests/cases/conformance/types/rest/differenceTypeAssignability.ts(47,5): error TS2322: Type 'BN' is not assignable to type 'T - "a"'.
tests/cases/conformance/types/rest/differenceTypeAssignability.ts(48,5): error TS2322: Type 'T - "a"' is not assignable to type 'BN'.
==== tests/cases/conformance/types/rest/differenceTypeAssignability.ts (14 errors) ====
type A = 'a';
type B = 'b';
type C = 'c';
type AB = A | B;
type AC = A | C;
type BN = { b: number };
function f<T extends 'x' | 'y' | 'z', U extends 'u', V extends string> (t: T, u: U, v: V) {
let t_u: T - U;
let t_v: T - V;
let u_t: U - T;
t_u = t; // ok
t_u = t_u; // ok
t_u = t_v; // error
~~~
!!! error TS2322: Type 'T - V' is not assignable to type 'T - U'.
!!! error TS2322: Type 'V' is not assignable to type 'U'.
!!! error TS2322: Type 'string' is not assignable to type 'U'.
t_u = u_t; // error
~~~
!!! error TS2322: Type 'U' is not assignable to type 'T'.
!!! error TS2322: Type '"u"' is not assignable to type 'T'.
var t_a: T - A;
var t_c: T - C;
var t_ab: T - AB;
var u_a: U - A;
t_a = t_a; // ok
t_ab = t_a; // ok
t_a = t; // ok
t_a = t_c; // error
~~~
!!! error TS2322: Type 'T - "c"' is not assignable to type 'T - "a"'.
!!! error TS2322: Type '"c"' is not assignable to type '"a"'.
t_a = t_ab; // error
~~~
!!! error TS2322: Type 'T - AB' is not assignable to type 'T - "a"'.
!!! error TS2322: Type 'AB' is not assignable to type '"a"'.
!!! error TS2322: Type '"b"' is not assignable to type '"a"'.
t = t_a; // error, T-a is missing 'a' if T contains 'a'
~
!!! error TS2322: Type 'T - "a"' is not assignable to type 'T'.
t_a = u_a; // error
~~~
!!! error TS2322: Type 'U' is not assignable to type 'T'.
!!! error TS2322: Type '"u"' is not assignable to type 'T'.
var ab_u: { a, b } - U;
var ab_t: { a, b } - T;
var a_t: { a } - T;
var ac_t: { a, c } - T;
ab_t = ab_t; // ok
a_t = ab_t; // ok
ab_t = a_t; // error
~~~~
!!! error TS2322: Type '{ a: any; }' is not assignable to type '{ a: any; b: any; }'.
!!! error TS2322: Property 'b' is missing in type '{ a: any; }'.
ab_u = ab_t; // error
~~~~
!!! error TS2322: Type '{ a: any; b: any; } - T' is not assignable to type '{ a: any; b: any; } - U'.
!!! error TS2322: Type 'T' is not assignable to type 'U'.
!!! error TS2322: Type '"x" | "y" | "z"' is not assignable to type 'U'.
!!! error TS2322: Type '"x"' is not assignable to type 'U'.
ab_t = ac_t // error
~~~~
!!! error TS2322: Type '{ a: any; c: any; }' is not assignable to type '{ a: any; b: any; }'.
!!! error TS2322: Property 'b' is missing in type '{ a: any; c: any; }'.
t_a = a_t; // error, this makes no sense.
~~~
!!! error TS2322: Type '{ a: any; }' is not assignable to type 'T'.
t_a = t_u; // error, let T and U contain property u. Then T-a has property u but T-U does not.
~~~
!!! error TS2322: Type 'T - U' is not assignable to type 'T - "a"'.
!!! error TS2322: Type 'U' is not assignable to type '"a"'.
!!! error TS2322: Type '"u"' is not assignable to type '"a"'.
t_u = t_a; // error, let T contain property a and U not. Then T-a has no a, but T-U does.
~~~
!!! error TS2322: Type 'T - "a"' is not assignable to type 'T - U'.
!!! error TS2322: Type '"a"' is not assignable to type 'U'.
var bn: BN;
t_a = bn; // error, we have no idea what T is supposed to be
~~~
!!! error TS2322: Type 'BN' is not assignable to type 'T - "a"'.
bn = t_a; // would be ok only if T extends BN
~~
!!! error TS2322: Type 'T - "a"' is not assignable to type 'BN'.
}

View file

@ -0,0 +1,88 @@
//// [differenceTypeAssignability.ts]
type A = 'a';
type B = 'b';
type C = 'c';
type AB = A | B;
type AC = A | C;
type BN = { b: number };
function f<T extends 'x' | 'y' | 'z', U extends 'u', V extends string> (t: T, u: U, v: V) {
let t_u: T - U;
let t_v: T - V;
let u_t: U - T;
t_u = t; // ok
t_u = t_u; // ok
t_u = t_v; // error
t_u = u_t; // error
var t_a: T - A;
var t_c: T - C;
var t_ab: T - AB;
var u_a: U - A;
t_a = t_a; // ok
t_ab = t_a; // ok
t_a = t; // ok
t_a = t_c; // error
t_a = t_ab; // error
t = t_a; // error, T-a is missing 'a' if T contains 'a'
t_a = u_a; // error
var ab_u: { a, b } - U;
var ab_t: { a, b } - T;
var a_t: { a } - T;
var ac_t: { a, c } - T;
ab_t = ab_t; // ok
a_t = ab_t; // ok
ab_t = a_t; // error
ab_u = ab_t; // error
ab_t = ac_t // error
t_a = a_t; // error, this makes no sense.
t_a = t_u; // error, let T and U contain property u. Then T-a has property u but T-U does not.
t_u = t_a; // error, let T contain property a and U not. Then T-a has no a, but T-U does.
var bn: BN;
t_a = bn; // error, we have no idea what T is supposed to be
bn = t_a; // would be ok only if T extends BN
}
//// [differenceTypeAssignability.js]
function f(t, u, v) {
var t_u;
var t_v;
var u_t;
t_u = t; // ok
t_u = t_u; // ok
t_u = t_v; // error
t_u = u_t; // error
var t_a;
var t_c;
var t_ab;
var u_a;
t_a = t_a; // ok
t_ab = t_a; // ok
t_a = t; // ok
t_a = t_c; // error
t_a = t_ab; // error
t = t_a; // error, T-a is missing 'a' if T contains 'a'
t_a = u_a; // error
var ab_u;
var ab_t;
var a_t;
var ac_t;
ab_t = ab_t; // ok
a_t = ab_t; // ok
ab_t = a_t; // error
ab_u = ab_t; // error
ab_t = ac_t; // error
t_a = a_t; // error, this makes no sense.
t_a = t_u; // error, let T and U contain property u. Then T-a has property u but T-U does not.
t_u = t_a; // error, let T contain property a and U not. Then T-a has no a, but T-U does.
var bn;
t_a = bn; // error, we have no idea what T is supposed to be
bn = t_a; // would be ok only if T extends BN
}

View file

@ -0,0 +1,65 @@
tests/cases/conformance/types/rest/differenceTypeNegative.ts(3,17): error TS2705: The right side of a difference type must be a string or string literal union, or a type parameter constrained to one of these.
tests/cases/conformance/types/rest/differenceTypeNegative.ts(4,17): error TS2705: The right side of a difference type must be a string or string literal union, or a type parameter constrained to one of these.
tests/cases/conformance/types/rest/differenceTypeNegative.ts(5,17): error TS2705: The right side of a difference type must be a string or string literal union, or a type parameter constrained to one of these.
tests/cases/conformance/types/rest/differenceTypeNegative.ts(6,17): error TS2705: The right side of a difference type must be a string or string literal union, or a type parameter constrained to one of these.
tests/cases/conformance/types/rest/differenceTypeNegative.ts(8,21): error TS2705: The right side of a difference type must be a string or string literal union, or a type parameter constrained to one of these.
tests/cases/conformance/types/rest/differenceTypeNegative.ts(9,21): error TS2705: The right side of a difference type must be a string or string literal union, or a type parameter constrained to one of these.
tests/cases/conformance/types/rest/differenceTypeNegative.ts(10,21): error TS2705: The right side of a difference type must be a string or string literal union, or a type parameter constrained to one of these.
tests/cases/conformance/types/rest/differenceTypeNegative.ts(11,21): error TS2705: The right side of a difference type must be a string or string literal union, or a type parameter constrained to one of these.
tests/cases/conformance/types/rest/differenceTypeNegative.ts(12,21): error TS2705: The right side of a difference type must be a string or string literal union, or a type parameter constrained to one of these.
tests/cases/conformance/types/rest/differenceTypeNegative.ts(18,5): error TS2322: Type 'U - keyof T' is not assignable to type 'U - keyof U'.
Type 'keyof T' is not assignable to type 'keyof U'.
Type 'keyof T' is not assignable to type '"toString" | "charAt" | "charCodeAt" | "concat" | "indexOf" | "lastIndexOf" | "localeCompare" | "match" | "replace" | "search" | "slice" | "split" | "substring" | "toLowerCase" | "toLocaleLowerCase" | "toUpperCase" | "toLocaleUpperCase" | "trim" | "length" | "substr" | "valueOf"'.
Type 'keyof T' is not assignable to type '"valueOf"'.
tests/cases/conformance/types/rest/differenceTypeNegative.ts(19,5): error TS2322: Type 'U - keyof U' is not assignable to type 'U - keyof T'.
Type 'keyof U' is not assignable to type 'keyof T'.
==== tests/cases/conformance/types/rest/differenceTypeNegative.ts (11 errors) ====
type Abc = { a; b; c }
type Surprise = 'a' | 'b' | 12;
let bad1: Abc - 12;
~~
!!! error TS2705: The right side of a difference type must be a string or string literal union, or a type parameter constrained to one of these.
let bad2: Abc - Surprise;
~~~~~~~~
!!! error TS2705: The right side of a difference type must be a string or string literal union, or a type parameter constrained to one of these.
let bad3: Abc - 'a' & 'b';
~~~~~~~~~
!!! error TS2705: The right side of a difference type must be a string or string literal union, or a type parameter constrained to one of these.
let bad4: Abc - number;
~~~~~~
!!! error TS2705: The right side of a difference type must be a string or string literal union, or a type parameter constrained to one of these.
function f<T, U extends 12, V extends Surprise, W extends 'a' & 'b', X extends number>(t: T) {
let bad1: Abc - T;
~
!!! error TS2705: The right side of a difference type must be a string or string literal union, or a type parameter constrained to one of these.
let bad2: Abc - 12;
~~
!!! error TS2705: The right side of a difference type must be a string or string literal union, or a type parameter constrained to one of these.
let bad3: Abc - Surprise;
~~~~~~~~
!!! error TS2705: The right side of a difference type must be a string or string literal union, or a type parameter constrained to one of these.
let bad4: Abc - 'a' & 'b';
~~~~~~~~~
!!! error TS2705: The right side of a difference type must be a string or string literal union, or a type parameter constrained to one of these.
let bad5: Abc - number;
~~~~~~
!!! error TS2705: The right side of a difference type must be a string or string literal union, or a type parameter constrained to one of these.
return bad1;
}
function g<T,U extends keyof Abc> (t: T, u: U) {
let usubtkey: U - keyof T;
let usubukey: U - keyof U;
usubukey = usubtkey;
~~~~~~~~
!!! error TS2322: Type 'U - keyof T' is not assignable to type 'U - keyof U'.
!!! error TS2322: Type 'keyof T' is not assignable to type 'keyof U'.
!!! error TS2322: Type 'keyof T' is not assignable to type '"toString" | "charAt" | "charCodeAt" | "concat" | "indexOf" | "lastIndexOf" | "localeCompare" | "match" | "replace" | "search" | "slice" | "split" | "substring" | "toLowerCase" | "toLocaleLowerCase" | "toUpperCase" | "toLocaleUpperCase" | "trim" | "length" | "substr" | "valueOf"'.
!!! error TS2322: Type 'keyof T' is not assignable to type '"valueOf"'.
usubtkey = usubukey;
~~~~~~~~
!!! error TS2322: Type 'U - keyof U' is not assignable to type 'U - keyof T'.
!!! error TS2322: Type 'keyof U' is not assignable to type 'keyof T'.
}

View file

@ -0,0 +1,42 @@
//// [differenceTypeNegative.ts]
type Abc = { a; b; c }
type Surprise = 'a' | 'b' | 12;
let bad1: Abc - 12;
let bad2: Abc - Surprise;
let bad3: Abc - 'a' & 'b';
let bad4: Abc - number;
function f<T, U extends 12, V extends Surprise, W extends 'a' & 'b', X extends number>(t: T) {
let bad1: Abc - T;
let bad2: Abc - 12;
let bad3: Abc - Surprise;
let bad4: Abc - 'a' & 'b';
let bad5: Abc - number;
return bad1;
}
function g<T,U extends keyof Abc> (t: T, u: U) {
let usubtkey: U - keyof T;
let usubukey: U - keyof U;
usubukey = usubtkey;
usubtkey = usubukey;
}
//// [differenceTypeNegative.js]
var bad1;
var bad2;
var bad3;
var bad4;
function f(t) {
var bad1;
var bad2;
var bad3;
var bad4;
var bad5;
return bad1;
}
function g(t, u) {
var usubtkey;
var usubukey;
usubukey = usubtkey;
usubtkey = usubukey;
}

View file

@ -1,16 +1,16 @@
tests/cases/compiler/dontShowCompilerGeneratedMembers.ts(1,5): error TS2322: Type 'number' is not assignable to type '{ (): any; x: number; }'.
tests/cases/compiler/dontShowCompilerGeneratedMembers.ts(3,6): error TS1139: Type parameter declaration expected.
tests/cases/compiler/dontShowCompilerGeneratedMembers.ts(4,1): error TS1109: Expression expected.
tests/cases/compiler/dontShowCompilerGeneratedMembers.ts(3,7): error TS2705: The right side of a difference type must be a string or string literal union, or a type parameter constrained to one of these.
tests/cases/compiler/dontShowCompilerGeneratedMembers.ts(4,1): error TS1110: Type expected.
==== tests/cases/compiler/dontShowCompilerGeneratedMembers.ts (3 errors) ====
var f: {
~
!!! error TS2322: Type 'number' is not assignable to type '{ (): any; x: number; }'.
x: number;
<-
~
!!! error TS1139: Type parameter declaration expected.
!!! error TS2705: The right side of a difference type must be a string or string literal union, or a type parameter constrained to one of these.
};
~
!!! error TS1109: Expression expected.
!!! error TS1110: Type expected.

View file

@ -5,5 +5,5 @@ var f: {
};
//// [dontShowCompilerGeneratedMembers.js]
var f = -;
var f;
;

View file

@ -0,0 +1,26 @@
type A = 'a';
type B = 'b';
type C = 'c';
type AB = A | B;
let nothing: A - 'a';
let none: AB - 'a' | 'b';
let over: 'a' - 'a' | 'b';
let under: 'a' | 'b' - 'a';
let partial: 'a' | 'b' - 'b' | 'd';
let empty: AB - AB;
let nope: string - string;
let nope2: 'a' | 'b' - string;
let nope3: string - 'a' | 'b';
type Abcd = { a; b; c; d }
function f<T,U extends keyof Abcd> (t: T, u: U) {
let usubtkey: U - keyof T;
let usubukey: U - keyof U;
usubtkey = usubtkey;
let tsubu: T - U;
return tsubu;
}
const x = f<'a' | 'b', 'b' | 'd'>('a', 'b');

View file

@ -0,0 +1,49 @@
type A = 'a';
type B = 'b';
type C = 'c';
type AB = A | B;
type AC = A | C;
type BN = { b: number };
function f<T extends 'x' | 'y' | 'z', U extends 'u', V extends string> (t: T, u: U, v: V) {
let t_u: T - U;
let t_v: T - V;
let u_t: U - T;
t_u = t; // ok
t_u = t_u; // ok
t_u = t_v; // error
t_u = u_t; // error
var t_a: T - A;
var t_c: T - C;
var t_ab: T - AB;
var u_a: U - A;
t_a = t_a; // ok
t_ab = t_a; // ok
t_a = t; // ok
t_a = t_c; // error
t_a = t_ab; // error
t = t_a; // error, T-a is missing 'a' if T contains 'a'
t_a = u_a; // error
var ab_u: { a, b } - U;
var ab_t: { a, b } - T;
var a_t: { a } - T;
var ac_t: { a, c } - T;
ab_t = ab_t; // ok
a_t = ab_t; // ok
ab_t = a_t; // error
ab_u = ab_t; // error
ab_t = ac_t // error
t_a = a_t; // error, this makes no sense.
t_a = t_u; // error, let T and U contain property u. Then T-a has property u but T-U does not.
t_u = t_a; // error, let T contain property a and U not. Then T-a has no a, but T-U does.
var bn: BN;
t_a = bn; // error, we have no idea what T is supposed to be
bn = t_a; // would be ok only if T extends BN
}

View file

@ -0,0 +1,20 @@
type Abc = { a; b; c }
type Surprise = 'a' | 'b' | 12;
let bad1: Abc - 12;
let bad2: Abc - Surprise;
let bad3: Abc - 'a' & 'b';
let bad4: Abc - number;
function f<T, U extends 12, V extends Surprise, W extends 'a' & 'b', X extends number>(t: T) {
let bad1: Abc - T;
let bad2: Abc - 12;
let bad3: Abc - Surprise;
let bad4: Abc - 'a' & 'b';
let bad5: Abc - number;
return bad1;
}
function g<T,U extends keyof Abc> (t: T, u: U) {
let usubtkey: U - keyof T;
let usubukey: U - keyof U;
usubukey = usubtkey;
usubtkey = usubukey;
}