mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Merge pull request #6947 from Microsoft/operatorsAndIntersections
Allow operators and indexing with intersections involving primtive types
This commit is contained in:
+41
-33
@@ -5591,7 +5591,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function hasExcessProperties(source: FreshObjectLiteralType, target: Type, reportErrors: boolean): boolean {
|
||||
if (!(target.flags & TypeFlags.ObjectLiteralPatternWithComputedProperties) && someConstituentTypeHasKind(target, TypeFlags.ObjectType)) {
|
||||
if (!(target.flags & TypeFlags.ObjectLiteralPatternWithComputedProperties) && maybeTypeOfKind(target, TypeFlags.ObjectType)) {
|
||||
for (const prop of getPropertiesOfObjectType(source)) {
|
||||
if (!isKnownProperty(target, prop.name)) {
|
||||
if (reportErrors) {
|
||||
@@ -8178,7 +8178,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function isTypeAnyOrAllConstituentTypesHaveKind(type: Type, kind: TypeFlags): boolean {
|
||||
return isTypeAny(type) || allConstituentTypesHaveKind(type, kind);
|
||||
return isTypeAny(type) || isTypeOfKind(type, kind);
|
||||
}
|
||||
|
||||
function isNumericLiteralName(name: string) {
|
||||
@@ -9684,7 +9684,7 @@ namespace ts {
|
||||
|
||||
case SyntaxKind.ComputedPropertyName:
|
||||
const nameType = checkComputedPropertyName(<ComputedPropertyName>element.name);
|
||||
if (allConstituentTypesHaveKind(nameType, TypeFlags.ESSymbol)) {
|
||||
if (isTypeOfKind(nameType, TypeFlags.ESSymbol)) {
|
||||
return nameType;
|
||||
}
|
||||
else {
|
||||
@@ -10337,9 +10337,8 @@ namespace ts {
|
||||
const widenedType = getWidenedType(exprType);
|
||||
|
||||
// Permit 'number[] | "foo"' to be asserted to 'string'.
|
||||
const bothAreStringLike =
|
||||
someConstituentTypeHasKind(targetType, TypeFlags.StringLike) &&
|
||||
someConstituentTypeHasKind(widenedType, TypeFlags.StringLike);
|
||||
const bothAreStringLike = maybeTypeOfKind(targetType, TypeFlags.StringLike) &&
|
||||
maybeTypeOfKind(widenedType, TypeFlags.StringLike);
|
||||
if (!bothAreStringLike && !(isTypeAssignableTo(targetType, widenedType))) {
|
||||
checkTypeAssignableTo(exprType, targetType, node, Diagnostics.Neither_type_0_nor_type_1_is_assignable_to_the_other);
|
||||
}
|
||||
@@ -10594,7 +10593,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
// Functions with with an explicitly specified 'void' or 'any' return type don't need any return expressions.
|
||||
if (returnType === voidType || isTypeAny(returnType) || (returnType && (returnType.flags & TypeFlags.Union) && someConstituentTypeHasKind(returnType, TypeFlags.Any | TypeFlags.Void))) {
|
||||
if (returnType && maybeTypeOfKind(returnType, TypeFlags.Any | TypeFlags.Void)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -10850,7 +10849,7 @@ namespace ts {
|
||||
case SyntaxKind.PlusToken:
|
||||
case SyntaxKind.MinusToken:
|
||||
case SyntaxKind.TildeToken:
|
||||
if (someConstituentTypeHasKind(operandType, TypeFlags.ESSymbol)) {
|
||||
if (maybeTypeOfKind(operandType, TypeFlags.ESSymbol)) {
|
||||
error(node.operand, Diagnostics.The_0_operator_cannot_be_applied_to_type_symbol, tokenToString(node.operator));
|
||||
}
|
||||
return numberType;
|
||||
@@ -10882,38 +10881,47 @@ namespace ts {
|
||||
return numberType;
|
||||
}
|
||||
|
||||
// Just like isTypeOfKind below, except that it returns true if *any* constituent
|
||||
// has this kind.
|
||||
function someConstituentTypeHasKind(type: Type, kind: TypeFlags): boolean {
|
||||
// Return true if type might be of the given kind. A union or intersection type might be of a given
|
||||
// kind if at least one constituent type is of the given kind.
|
||||
function maybeTypeOfKind(type: Type, kind: TypeFlags): boolean {
|
||||
if (type.flags & kind) {
|
||||
return true;
|
||||
}
|
||||
if (type.flags & TypeFlags.UnionOrIntersection) {
|
||||
const types = (<UnionOrIntersectionType>type).types;
|
||||
for (const current of types) {
|
||||
if (current.flags & kind) {
|
||||
for (const t of types) {
|
||||
if (maybeTypeOfKind(t, kind)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Return true if type has the given flags, or is a union or intersection type composed of types that all have those flags.
|
||||
function allConstituentTypesHaveKind(type: Type, kind: TypeFlags): boolean {
|
||||
// Return true if type is of the given kind. A union type is of a given kind if all constituent types
|
||||
// are of the given kind. An intersection type is of a given kind if at least one constituent type is
|
||||
// of the given kind.
|
||||
function isTypeOfKind(type: Type, kind: TypeFlags): boolean {
|
||||
if (type.flags & kind) {
|
||||
return true;
|
||||
}
|
||||
if (type.flags & TypeFlags.UnionOrIntersection) {
|
||||
if (type.flags & TypeFlags.Union) {
|
||||
const types = (<UnionOrIntersectionType>type).types;
|
||||
for (const current of types) {
|
||||
if (!(current.flags & kind)) {
|
||||
for (const t of types) {
|
||||
if (!isTypeOfKind(t, kind)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (type.flags & TypeFlags.Intersection) {
|
||||
const types = (<UnionOrIntersectionType>type).types;
|
||||
for (const t of types) {
|
||||
if (isTypeOfKind(t, kind)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -10931,7 +10939,7 @@ namespace ts {
|
||||
// and the right operand to be of type Any or a subtype of the 'Function' interface type.
|
||||
// The result is always of the Boolean primitive type.
|
||||
// NOTE: do not raise error if leftType is unknown as related error was already reported
|
||||
if (allConstituentTypesHaveKind(leftType, TypeFlags.Primitive)) {
|
||||
if (isTypeOfKind(leftType, TypeFlags.Primitive)) {
|
||||
error(left, Diagnostics.The_left_hand_side_of_an_instanceof_expression_must_be_of_type_any_an_object_type_or_a_type_parameter);
|
||||
}
|
||||
// NOTE: do not raise error if right is unknown as related error was already reported
|
||||
@@ -11146,13 +11154,13 @@ namespace ts {
|
||||
if (rightType.flags & (TypeFlags.Undefined | TypeFlags.Null)) rightType = leftType;
|
||||
|
||||
let resultType: Type;
|
||||
if (allConstituentTypesHaveKind(leftType, TypeFlags.NumberLike) && allConstituentTypesHaveKind(rightType, TypeFlags.NumberLike)) {
|
||||
if (isTypeOfKind(leftType, TypeFlags.NumberLike) && isTypeOfKind(rightType, TypeFlags.NumberLike)) {
|
||||
// Operands of an enum type are treated as having the primitive type Number.
|
||||
// If both operands are of the Number primitive type, the result is of the Number primitive type.
|
||||
resultType = numberType;
|
||||
}
|
||||
else {
|
||||
if (allConstituentTypesHaveKind(leftType, TypeFlags.StringLike) || allConstituentTypesHaveKind(rightType, TypeFlags.StringLike)) {
|
||||
if (isTypeOfKind(leftType, TypeFlags.StringLike) || isTypeOfKind(rightType, TypeFlags.StringLike)) {
|
||||
// If one or both operands are of the String primitive type, the result is of the String primitive type.
|
||||
resultType = stringType;
|
||||
}
|
||||
@@ -11190,7 +11198,7 @@ namespace ts {
|
||||
case SyntaxKind.EqualsEqualsEqualsToken:
|
||||
case SyntaxKind.ExclamationEqualsEqualsToken:
|
||||
// Permit 'number[] | "foo"' to be asserted to 'string'.
|
||||
if (someConstituentTypeHasKind(leftType, TypeFlags.StringLike) && someConstituentTypeHasKind(rightType, TypeFlags.StringLike)) {
|
||||
if (maybeTypeOfKind(leftType, TypeFlags.StringLike) && maybeTypeOfKind(rightType, TypeFlags.StringLike)) {
|
||||
return booleanType;
|
||||
}
|
||||
if (!isTypeAssignableTo(leftType, rightType) && !isTypeAssignableTo(rightType, leftType)) {
|
||||
@@ -11215,8 +11223,8 @@ namespace ts {
|
||||
// Return true if there was no error, false if there was an error.
|
||||
function checkForDisallowedESSymbolOperand(operator: SyntaxKind): boolean {
|
||||
const offendingSymbolOperand =
|
||||
someConstituentTypeHasKind(leftType, TypeFlags.ESSymbol) ? left :
|
||||
someConstituentTypeHasKind(rightType, TypeFlags.ESSymbol) ? right :
|
||||
maybeTypeOfKind(leftType, TypeFlags.ESSymbol) ? left :
|
||||
maybeTypeOfKind(rightType, TypeFlags.ESSymbol) ? right :
|
||||
undefined;
|
||||
if (offendingSymbolOperand) {
|
||||
error(offendingSymbolOperand, Diagnostics.The_0_operator_cannot_be_applied_to_type_symbol, tokenToString(operator));
|
||||
@@ -13700,7 +13708,7 @@ namespace ts {
|
||||
let hasDuplicateDefaultClause = false;
|
||||
|
||||
const expressionType = checkExpression(node.expression);
|
||||
const expressionTypeIsStringLike = someConstituentTypeHasKind(expressionType, TypeFlags.StringLike);
|
||||
const expressionTypeIsStringLike = maybeTypeOfKind(expressionType, TypeFlags.StringLike);
|
||||
forEach(node.caseBlock.clauses, clause => {
|
||||
// Grammar check for duplicate default clauses, skip if we already report duplicate default clause
|
||||
if (clause.kind === SyntaxKind.DefaultClause && !hasDuplicateDefaultClause) {
|
||||
@@ -13724,7 +13732,7 @@ namespace ts {
|
||||
|
||||
const expressionTypeIsAssignableToCaseType =
|
||||
// Permit 'number[] | "foo"' to be asserted to 'string'.
|
||||
(expressionTypeIsStringLike && someConstituentTypeHasKind(caseType, TypeFlags.StringLike)) ||
|
||||
(expressionTypeIsStringLike && maybeTypeOfKind(caseType, TypeFlags.StringLike)) ||
|
||||
isTypeAssignableTo(expressionType, caseType);
|
||||
|
||||
if (!expressionTypeIsAssignableToCaseType) {
|
||||
@@ -15930,22 +15938,22 @@ namespace ts {
|
||||
else if (type.flags & TypeFlags.Any) {
|
||||
return TypeReferenceSerializationKind.ObjectType;
|
||||
}
|
||||
else if (allConstituentTypesHaveKind(type, TypeFlags.Void)) {
|
||||
else if (isTypeOfKind(type, TypeFlags.Void)) {
|
||||
return TypeReferenceSerializationKind.VoidType;
|
||||
}
|
||||
else if (allConstituentTypesHaveKind(type, TypeFlags.Boolean)) {
|
||||
else if (isTypeOfKind(type, TypeFlags.Boolean)) {
|
||||
return TypeReferenceSerializationKind.BooleanType;
|
||||
}
|
||||
else if (allConstituentTypesHaveKind(type, TypeFlags.NumberLike)) {
|
||||
else if (isTypeOfKind(type, TypeFlags.NumberLike)) {
|
||||
return TypeReferenceSerializationKind.NumberLikeType;
|
||||
}
|
||||
else if (allConstituentTypesHaveKind(type, TypeFlags.StringLike)) {
|
||||
else if (isTypeOfKind(type, TypeFlags.StringLike)) {
|
||||
return TypeReferenceSerializationKind.StringLikeType;
|
||||
}
|
||||
else if (allConstituentTypesHaveKind(type, TypeFlags.Tuple)) {
|
||||
else if (isTypeOfKind(type, TypeFlags.Tuple)) {
|
||||
return TypeReferenceSerializationKind.ArrayLikeType;
|
||||
}
|
||||
else if (allConstituentTypesHaveKind(type, TypeFlags.ESSymbol)) {
|
||||
else if (isTypeOfKind(type, TypeFlags.ESSymbol)) {
|
||||
return TypeReferenceSerializationKind.ESSymbolType;
|
||||
}
|
||||
else if (isFunctionType(type)) {
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
//// [operatorsAndIntersectionTypes.ts]
|
||||
type Guid = string & { $Guid }; // Tagged string type
|
||||
type SerialNo = number & { $SerialNo }; // Tagged number type
|
||||
|
||||
function createGuid() {
|
||||
return "21EC2020-3AEA-4069-A2DD-08002B30309D" as Guid;
|
||||
}
|
||||
|
||||
function createSerialNo() {
|
||||
return 12345 as SerialNo;
|
||||
}
|
||||
|
||||
let map1: { [x: string]: number } = {};
|
||||
let guid = createGuid();
|
||||
map1[guid] = 123; // Can with tagged string
|
||||
|
||||
let map2: { [x: number]: string } = {};
|
||||
let serialNo = createSerialNo();
|
||||
map2[serialNo] = "hello"; // Can index with tagged number
|
||||
|
||||
const s1 = "{" + guid + "}";
|
||||
const s2 = guid.toLowerCase();
|
||||
const s3 = guid + guid;
|
||||
const s4 = guid + serialNo;
|
||||
const s5 = serialNo.toPrecision(0);
|
||||
const n1 = serialNo * 3;
|
||||
const n2 = serialNo + serialNo;
|
||||
const b1 = guid === "";
|
||||
const b2 = guid === guid;
|
||||
const b3 = serialNo === 0;
|
||||
const b4 = serialNo === serialNo;
|
||||
|
||||
|
||||
//// [operatorsAndIntersectionTypes.js]
|
||||
function createGuid() {
|
||||
return "21EC2020-3AEA-4069-A2DD-08002B30309D";
|
||||
}
|
||||
function createSerialNo() {
|
||||
return 12345;
|
||||
}
|
||||
var map1 = {};
|
||||
var guid = createGuid();
|
||||
map1[guid] = 123; // Can with tagged string
|
||||
var map2 = {};
|
||||
var serialNo = createSerialNo();
|
||||
map2[serialNo] = "hello"; // Can index with tagged number
|
||||
var s1 = "{" + guid + "}";
|
||||
var s2 = guid.toLowerCase();
|
||||
var s3 = guid + guid;
|
||||
var s4 = guid + serialNo;
|
||||
var s5 = serialNo.toPrecision(0);
|
||||
var n1 = serialNo * 3;
|
||||
var n2 = serialNo + serialNo;
|
||||
var b1 = guid === "";
|
||||
var b2 = guid === guid;
|
||||
var b3 = serialNo === 0;
|
||||
var b4 = serialNo === serialNo;
|
||||
@@ -0,0 +1,100 @@
|
||||
=== tests/cases/conformance/types/intersection/operatorsAndIntersectionTypes.ts ===
|
||||
type Guid = string & { $Guid }; // Tagged string type
|
||||
>Guid : Symbol(Guid, Decl(operatorsAndIntersectionTypes.ts, 0, 0))
|
||||
>$Guid : Symbol($Guid, Decl(operatorsAndIntersectionTypes.ts, 0, 22))
|
||||
|
||||
type SerialNo = number & { $SerialNo }; // Tagged number type
|
||||
>SerialNo : Symbol(SerialNo, Decl(operatorsAndIntersectionTypes.ts, 0, 31))
|
||||
>$SerialNo : Symbol($SerialNo, Decl(operatorsAndIntersectionTypes.ts, 1, 26))
|
||||
|
||||
function createGuid() {
|
||||
>createGuid : Symbol(createGuid, Decl(operatorsAndIntersectionTypes.ts, 1, 39))
|
||||
|
||||
return "21EC2020-3AEA-4069-A2DD-08002B30309D" as Guid;
|
||||
>Guid : Symbol(Guid, Decl(operatorsAndIntersectionTypes.ts, 0, 0))
|
||||
}
|
||||
|
||||
function createSerialNo() {
|
||||
>createSerialNo : Symbol(createSerialNo, Decl(operatorsAndIntersectionTypes.ts, 5, 1))
|
||||
|
||||
return 12345 as SerialNo;
|
||||
>SerialNo : Symbol(SerialNo, Decl(operatorsAndIntersectionTypes.ts, 0, 31))
|
||||
}
|
||||
|
||||
let map1: { [x: string]: number } = {};
|
||||
>map1 : Symbol(map1, Decl(operatorsAndIntersectionTypes.ts, 11, 3))
|
||||
>x : Symbol(x, Decl(operatorsAndIntersectionTypes.ts, 11, 13))
|
||||
|
||||
let guid = createGuid();
|
||||
>guid : Symbol(guid, Decl(operatorsAndIntersectionTypes.ts, 12, 3))
|
||||
>createGuid : Symbol(createGuid, Decl(operatorsAndIntersectionTypes.ts, 1, 39))
|
||||
|
||||
map1[guid] = 123; // Can with tagged string
|
||||
>map1 : Symbol(map1, Decl(operatorsAndIntersectionTypes.ts, 11, 3))
|
||||
>guid : Symbol(guid, Decl(operatorsAndIntersectionTypes.ts, 12, 3))
|
||||
|
||||
let map2: { [x: number]: string } = {};
|
||||
>map2 : Symbol(map2, Decl(operatorsAndIntersectionTypes.ts, 15, 3))
|
||||
>x : Symbol(x, Decl(operatorsAndIntersectionTypes.ts, 15, 13))
|
||||
|
||||
let serialNo = createSerialNo();
|
||||
>serialNo : Symbol(serialNo, Decl(operatorsAndIntersectionTypes.ts, 16, 3))
|
||||
>createSerialNo : Symbol(createSerialNo, Decl(operatorsAndIntersectionTypes.ts, 5, 1))
|
||||
|
||||
map2[serialNo] = "hello"; // Can index with tagged number
|
||||
>map2 : Symbol(map2, Decl(operatorsAndIntersectionTypes.ts, 15, 3))
|
||||
>serialNo : Symbol(serialNo, Decl(operatorsAndIntersectionTypes.ts, 16, 3))
|
||||
|
||||
const s1 = "{" + guid + "}";
|
||||
>s1 : Symbol(s1, Decl(operatorsAndIntersectionTypes.ts, 19, 5))
|
||||
>guid : Symbol(guid, Decl(operatorsAndIntersectionTypes.ts, 12, 3))
|
||||
|
||||
const s2 = guid.toLowerCase();
|
||||
>s2 : Symbol(s2, Decl(operatorsAndIntersectionTypes.ts, 20, 5))
|
||||
>guid.toLowerCase : Symbol(String.toLowerCase, Decl(lib.d.ts, --, --))
|
||||
>guid : Symbol(guid, Decl(operatorsAndIntersectionTypes.ts, 12, 3))
|
||||
>toLowerCase : Symbol(String.toLowerCase, Decl(lib.d.ts, --, --))
|
||||
|
||||
const s3 = guid + guid;
|
||||
>s3 : Symbol(s3, Decl(operatorsAndIntersectionTypes.ts, 21, 5))
|
||||
>guid : Symbol(guid, Decl(operatorsAndIntersectionTypes.ts, 12, 3))
|
||||
>guid : Symbol(guid, Decl(operatorsAndIntersectionTypes.ts, 12, 3))
|
||||
|
||||
const s4 = guid + serialNo;
|
||||
>s4 : Symbol(s4, Decl(operatorsAndIntersectionTypes.ts, 22, 5))
|
||||
>guid : Symbol(guid, Decl(operatorsAndIntersectionTypes.ts, 12, 3))
|
||||
>serialNo : Symbol(serialNo, Decl(operatorsAndIntersectionTypes.ts, 16, 3))
|
||||
|
||||
const s5 = serialNo.toPrecision(0);
|
||||
>s5 : Symbol(s5, Decl(operatorsAndIntersectionTypes.ts, 23, 5))
|
||||
>serialNo.toPrecision : Symbol(Number.toPrecision, Decl(lib.d.ts, --, --))
|
||||
>serialNo : Symbol(serialNo, Decl(operatorsAndIntersectionTypes.ts, 16, 3))
|
||||
>toPrecision : Symbol(Number.toPrecision, Decl(lib.d.ts, --, --))
|
||||
|
||||
const n1 = serialNo * 3;
|
||||
>n1 : Symbol(n1, Decl(operatorsAndIntersectionTypes.ts, 24, 5))
|
||||
>serialNo : Symbol(serialNo, Decl(operatorsAndIntersectionTypes.ts, 16, 3))
|
||||
|
||||
const n2 = serialNo + serialNo;
|
||||
>n2 : Symbol(n2, Decl(operatorsAndIntersectionTypes.ts, 25, 5))
|
||||
>serialNo : Symbol(serialNo, Decl(operatorsAndIntersectionTypes.ts, 16, 3))
|
||||
>serialNo : Symbol(serialNo, Decl(operatorsAndIntersectionTypes.ts, 16, 3))
|
||||
|
||||
const b1 = guid === "";
|
||||
>b1 : Symbol(b1, Decl(operatorsAndIntersectionTypes.ts, 26, 5))
|
||||
>guid : Symbol(guid, Decl(operatorsAndIntersectionTypes.ts, 12, 3))
|
||||
|
||||
const b2 = guid === guid;
|
||||
>b2 : Symbol(b2, Decl(operatorsAndIntersectionTypes.ts, 27, 5))
|
||||
>guid : Symbol(guid, Decl(operatorsAndIntersectionTypes.ts, 12, 3))
|
||||
>guid : Symbol(guid, Decl(operatorsAndIntersectionTypes.ts, 12, 3))
|
||||
|
||||
const b3 = serialNo === 0;
|
||||
>b3 : Symbol(b3, Decl(operatorsAndIntersectionTypes.ts, 28, 5))
|
||||
>serialNo : Symbol(serialNo, Decl(operatorsAndIntersectionTypes.ts, 16, 3))
|
||||
|
||||
const b4 = serialNo === serialNo;
|
||||
>b4 : Symbol(b4, Decl(operatorsAndIntersectionTypes.ts, 29, 5))
|
||||
>serialNo : Symbol(serialNo, Decl(operatorsAndIntersectionTypes.ts, 16, 3))
|
||||
>serialNo : Symbol(serialNo, Decl(operatorsAndIntersectionTypes.ts, 16, 3))
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
=== tests/cases/conformance/types/intersection/operatorsAndIntersectionTypes.ts ===
|
||||
type Guid = string & { $Guid }; // Tagged string type
|
||||
>Guid : string & { $Guid: any; }
|
||||
>$Guid : any
|
||||
|
||||
type SerialNo = number & { $SerialNo }; // Tagged number type
|
||||
>SerialNo : number & { $SerialNo: any; }
|
||||
>$SerialNo : any
|
||||
|
||||
function createGuid() {
|
||||
>createGuid : () => string & { $Guid: any; }
|
||||
|
||||
return "21EC2020-3AEA-4069-A2DD-08002B30309D" as Guid;
|
||||
>"21EC2020-3AEA-4069-A2DD-08002B30309D" as Guid : string & { $Guid: any; }
|
||||
>"21EC2020-3AEA-4069-A2DD-08002B30309D" : string
|
||||
>Guid : string & { $Guid: any; }
|
||||
}
|
||||
|
||||
function createSerialNo() {
|
||||
>createSerialNo : () => number & { $SerialNo: any; }
|
||||
|
||||
return 12345 as SerialNo;
|
||||
>12345 as SerialNo : number & { $SerialNo: any; }
|
||||
>12345 : number
|
||||
>SerialNo : number & { $SerialNo: any; }
|
||||
}
|
||||
|
||||
let map1: { [x: string]: number } = {};
|
||||
>map1 : { [x: string]: number; }
|
||||
>x : string
|
||||
>{} : { [x: string]: undefined; }
|
||||
|
||||
let guid = createGuid();
|
||||
>guid : string & { $Guid: any; }
|
||||
>createGuid() : string & { $Guid: any; }
|
||||
>createGuid : () => string & { $Guid: any; }
|
||||
|
||||
map1[guid] = 123; // Can with tagged string
|
||||
>map1[guid] = 123 : number
|
||||
>map1[guid] : number
|
||||
>map1 : { [x: string]: number; }
|
||||
>guid : string & { $Guid: any; }
|
||||
>123 : number
|
||||
|
||||
let map2: { [x: number]: string } = {};
|
||||
>map2 : { [x: number]: string; }
|
||||
>x : number
|
||||
>{} : { [x: number]: undefined; }
|
||||
|
||||
let serialNo = createSerialNo();
|
||||
>serialNo : number & { $SerialNo: any; }
|
||||
>createSerialNo() : number & { $SerialNo: any; }
|
||||
>createSerialNo : () => number & { $SerialNo: any; }
|
||||
|
||||
map2[serialNo] = "hello"; // Can index with tagged number
|
||||
>map2[serialNo] = "hello" : string
|
||||
>map2[serialNo] : string
|
||||
>map2 : { [x: number]: string; }
|
||||
>serialNo : number & { $SerialNo: any; }
|
||||
>"hello" : string
|
||||
|
||||
const s1 = "{" + guid + "}";
|
||||
>s1 : string
|
||||
>"{" + guid + "}" : string
|
||||
>"{" + guid : string
|
||||
>"{" : string
|
||||
>guid : string & { $Guid: any; }
|
||||
>"}" : string
|
||||
|
||||
const s2 = guid.toLowerCase();
|
||||
>s2 : string
|
||||
>guid.toLowerCase() : string
|
||||
>guid.toLowerCase : () => string
|
||||
>guid : string & { $Guid: any; }
|
||||
>toLowerCase : () => string
|
||||
|
||||
const s3 = guid + guid;
|
||||
>s3 : string
|
||||
>guid + guid : string
|
||||
>guid : string & { $Guid: any; }
|
||||
>guid : string & { $Guid: any; }
|
||||
|
||||
const s4 = guid + serialNo;
|
||||
>s4 : string
|
||||
>guid + serialNo : string
|
||||
>guid : string & { $Guid: any; }
|
||||
>serialNo : number & { $SerialNo: any; }
|
||||
|
||||
const s5 = serialNo.toPrecision(0);
|
||||
>s5 : string
|
||||
>serialNo.toPrecision(0) : string
|
||||
>serialNo.toPrecision : (precision?: number) => string
|
||||
>serialNo : number & { $SerialNo: any; }
|
||||
>toPrecision : (precision?: number) => string
|
||||
>0 : number
|
||||
|
||||
const n1 = serialNo * 3;
|
||||
>n1 : number
|
||||
>serialNo * 3 : number
|
||||
>serialNo : number & { $SerialNo: any; }
|
||||
>3 : number
|
||||
|
||||
const n2 = serialNo + serialNo;
|
||||
>n2 : number
|
||||
>serialNo + serialNo : number
|
||||
>serialNo : number & { $SerialNo: any; }
|
||||
>serialNo : number & { $SerialNo: any; }
|
||||
|
||||
const b1 = guid === "";
|
||||
>b1 : boolean
|
||||
>guid === "" : boolean
|
||||
>guid : string & { $Guid: any; }
|
||||
>"" : string
|
||||
|
||||
const b2 = guid === guid;
|
||||
>b2 : boolean
|
||||
>guid === guid : boolean
|
||||
>guid : string & { $Guid: any; }
|
||||
>guid : string & { $Guid: any; }
|
||||
|
||||
const b3 = serialNo === 0;
|
||||
>b3 : boolean
|
||||
>serialNo === 0 : boolean
|
||||
>serialNo : number & { $SerialNo: any; }
|
||||
>0 : number
|
||||
|
||||
const b4 = serialNo === serialNo;
|
||||
>b4 : boolean
|
||||
>serialNo === serialNo : boolean
|
||||
>serialNo : number & { $SerialNo: any; }
|
||||
>serialNo : number & { $SerialNo: any; }
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
type Guid = string & { $Guid }; // Tagged string type
|
||||
type SerialNo = number & { $SerialNo }; // Tagged number type
|
||||
|
||||
function createGuid() {
|
||||
return "21EC2020-3AEA-4069-A2DD-08002B30309D" as Guid;
|
||||
}
|
||||
|
||||
function createSerialNo() {
|
||||
return 12345 as SerialNo;
|
||||
}
|
||||
|
||||
let map1: { [x: string]: number } = {};
|
||||
let guid = createGuid();
|
||||
map1[guid] = 123; // Can with tagged string
|
||||
|
||||
let map2: { [x: number]: string } = {};
|
||||
let serialNo = createSerialNo();
|
||||
map2[serialNo] = "hello"; // Can index with tagged number
|
||||
|
||||
const s1 = "{" + guid + "}";
|
||||
const s2 = guid.toLowerCase();
|
||||
const s3 = guid + guid;
|
||||
const s4 = guid + serialNo;
|
||||
const s5 = serialNo.toPrecision(0);
|
||||
const n1 = serialNo * 3;
|
||||
const n2 = serialNo + serialNo;
|
||||
const b1 = guid === "";
|
||||
const b2 = guid === guid;
|
||||
const b3 = serialNo === 0;
|
||||
const b4 = serialNo === serialNo;
|
||||
Reference in New Issue
Block a user