Narrow on element access of literal (#26424)
* Narrow literal element accesses This means that, for example, the tuple `[number, string?]` allows its second element to be narrowed with element access: ```ts export function f(pair: [number, string?]): string { return pair[1] ? pair[1] : 'nope'; } ``` * Update baselines * Cleanup * More cleanup * Test dashes in property names * More cleanup * Delete undead code
This commit is contained in:
parent
b9bd0d9a3f
commit
2bfd919b6a
|
@ -723,6 +723,7 @@ namespace ts {
|
|||
case SyntaxKind.Identifier:
|
||||
case SyntaxKind.ThisKeyword:
|
||||
case SyntaxKind.PropertyAccessExpression:
|
||||
case SyntaxKind.ElementAccessExpression:
|
||||
return isNarrowableReference(expr);
|
||||
case SyntaxKind.CallExpression:
|
||||
return hasNarrowableArgument(<CallExpression>expr);
|
||||
|
@ -737,10 +738,11 @@ namespace ts {
|
|||
}
|
||||
|
||||
function isNarrowableReference(expr: Expression): boolean {
|
||||
return expr.kind === SyntaxKind.Identifier ||
|
||||
expr.kind === SyntaxKind.ThisKeyword ||
|
||||
expr.kind === SyntaxKind.SuperKeyword ||
|
||||
expr.kind === SyntaxKind.PropertyAccessExpression && isNarrowableReference((<PropertyAccessExpression>expr).expression);
|
||||
return expr.kind === SyntaxKind.Identifier || expr.kind === SyntaxKind.ThisKeyword || expr.kind === SyntaxKind.SuperKeyword ||
|
||||
isPropertyAccessExpression(expr) && isNarrowableReference(expr.expression) ||
|
||||
isElementAccessExpression(expr) && expr.argumentExpression &&
|
||||
(isStringLiteral(expr.argumentExpression) || isNumericLiteral(expr.argumentExpression)) &&
|
||||
isNarrowableReference(expr.expression);
|
||||
}
|
||||
|
||||
function hasNarrowableArgument(expr: CallExpression) {
|
||||
|
@ -2066,6 +2068,7 @@ namespace ts {
|
|||
}
|
||||
return checkStrictModeIdentifier(<Identifier>node);
|
||||
case SyntaxKind.PropertyAccessExpression:
|
||||
case SyntaxKind.ElementAccessExpression:
|
||||
if (currentFlow && isNarrowableReference(<Expression>node)) {
|
||||
node.flowNode = currentFlow;
|
||||
}
|
||||
|
|
|
@ -9158,7 +9158,8 @@ namespace ts {
|
|||
getNodeLinks(accessNode!).resolvedSymbol = prop;
|
||||
}
|
||||
}
|
||||
return getTypeOfSymbol(prop);
|
||||
const propType = getTypeOfSymbol(prop);
|
||||
return accessExpression ? getFlowTypeOfReference(accessExpression, propType) : propType;
|
||||
}
|
||||
if (isTupleType(objectType)) {
|
||||
const restType = getRestTypeOfTupleType(objectType);
|
||||
|
@ -13778,9 +13779,10 @@ namespace ts {
|
|||
case SyntaxKind.SuperKeyword:
|
||||
return target.kind === SyntaxKind.SuperKeyword;
|
||||
case SyntaxKind.PropertyAccessExpression:
|
||||
return target.kind === SyntaxKind.PropertyAccessExpression &&
|
||||
(<PropertyAccessExpression>source).name.escapedText === (<PropertyAccessExpression>target).name.escapedText &&
|
||||
isMatchingReference((<PropertyAccessExpression>source).expression, (<PropertyAccessExpression>target).expression);
|
||||
case SyntaxKind.ElementAccessExpression:
|
||||
return (isPropertyAccessExpression(target) || isElementAccessExpression(target)) &&
|
||||
getAccessedPropertyName(source as PropertyAccessExpression | ElementAccessExpression) === getAccessedPropertyName(target) &&
|
||||
isMatchingReference((source as PropertyAccessExpression | ElementAccessExpression).expression, target.expression);
|
||||
case SyntaxKind.BindingElement:
|
||||
if (target.kind !== SyntaxKind.PropertyAccessExpression) return false;
|
||||
const t = target as PropertyAccessExpression;
|
||||
|
@ -13796,6 +13798,12 @@ namespace ts {
|
|||
return false;
|
||||
}
|
||||
|
||||
function getAccessedPropertyName(access: PropertyAccessExpression | ElementAccessExpression): __String | undefined {
|
||||
return isPropertyAccessExpression(access) ? access.name.escapedText :
|
||||
isStringLiteral(access.argumentExpression) || isNumericLiteral(access.argumentExpression) ? escapeLeadingUnderscores(access.argumentExpression.text) :
|
||||
undefined;
|
||||
}
|
||||
|
||||
function containsMatchingReference(source: Node, target: Node) {
|
||||
while (source.kind === SyntaxKind.PropertyAccessExpression) {
|
||||
source = (<PropertyAccessExpression>source).expression;
|
||||
|
@ -14438,7 +14446,10 @@ namespace ts {
|
|||
else if (flags & FlowFlags.Start) {
|
||||
// Check if we should continue with the control flow of the containing function.
|
||||
const container = (<FlowStart>flow).container;
|
||||
if (container && container !== flowContainer && reference.kind !== SyntaxKind.PropertyAccessExpression && reference.kind !== SyntaxKind.ThisKeyword) {
|
||||
if (container && container !== flowContainer &&
|
||||
reference.kind !== SyntaxKind.PropertyAccessExpression &&
|
||||
reference.kind !== SyntaxKind.ElementAccessExpression &&
|
||||
reference.kind !== SyntaxKind.ThisKeyword) {
|
||||
flow = container.flowNode!;
|
||||
continue;
|
||||
}
|
||||
|
@ -14555,7 +14566,10 @@ namespace ts {
|
|||
type = narrowTypeBySwitchOnDiscriminant(type, flow.switchStatement, flow.clauseStart, flow.clauseEnd);
|
||||
}
|
||||
else if (isMatchingReferenceDiscriminant(expr, type)) {
|
||||
type = narrowTypeByDiscriminant(type, <PropertyAccessExpression>expr, t => narrowTypeBySwitchOnDiscriminant(t, flow.switchStatement, flow.clauseStart, flow.clauseEnd));
|
||||
type = narrowTypeByDiscriminant(
|
||||
type,
|
||||
expr as PropertyAccessExpression | ElementAccessExpression,
|
||||
t => narrowTypeBySwitchOnDiscriminant(t, flow.switchStatement, flow.clauseStart, flow.clauseEnd));
|
||||
}
|
||||
return createFlowType(type, isIncomplete(flowType));
|
||||
}
|
||||
|
@ -14671,14 +14685,23 @@ namespace ts {
|
|||
}
|
||||
|
||||
function isMatchingReferenceDiscriminant(expr: Expression, computedType: Type) {
|
||||
return expr.kind === SyntaxKind.PropertyAccessExpression &&
|
||||
computedType.flags & TypeFlags.Union &&
|
||||
isMatchingReference(reference, (<PropertyAccessExpression>expr).expression) &&
|
||||
isDiscriminantProperty(computedType, (<PropertyAccessExpression>expr).name.escapedText);
|
||||
if (!(computedType.flags & TypeFlags.Union) ||
|
||||
expr.kind !== SyntaxKind.PropertyAccessExpression && expr.kind !== SyntaxKind.ElementAccessExpression) {
|
||||
return false;
|
||||
}
|
||||
const access = expr as PropertyAccessExpression | ElementAccessExpression;
|
||||
const name = getAccessedPropertyName(access);
|
||||
if (!name) {
|
||||
return false;
|
||||
}
|
||||
return isMatchingReference(reference, access.expression) && isDiscriminantProperty(computedType, name);
|
||||
}
|
||||
|
||||
function narrowTypeByDiscriminant(type: Type, propAccess: PropertyAccessExpression, narrowType: (t: Type) => Type): Type {
|
||||
const propName = propAccess.name.escapedText;
|
||||
function narrowTypeByDiscriminant(type: Type, access: PropertyAccessExpression | ElementAccessExpression, narrowType: (t: Type) => Type): Type {
|
||||
const propName = getAccessedPropertyName(access);
|
||||
if (!propName) {
|
||||
return type;
|
||||
}
|
||||
const propType = getTypeOfPropertyOfType(type, propName);
|
||||
const narrowedPropType = propType && narrowType(propType);
|
||||
return propType === narrowedPropType ? type : filterType(type, t => isTypeComparableTo(getTypeOfPropertyOfType(t, propName)!, narrowedPropType!));
|
||||
|
@ -14689,7 +14712,7 @@ namespace ts {
|
|||
return getTypeWithFacts(type, assumeTrue ? TypeFacts.Truthy : TypeFacts.Falsy);
|
||||
}
|
||||
if (isMatchingReferenceDiscriminant(expr, declaredType)) {
|
||||
return narrowTypeByDiscriminant(type, <PropertyAccessExpression>expr, t => getTypeWithFacts(t, assumeTrue ? TypeFacts.Truthy : TypeFacts.Falsy));
|
||||
return narrowTypeByDiscriminant(type, <PropertyAccessExpression | ElementAccessExpression>expr, t => getTypeWithFacts(t, assumeTrue ? TypeFacts.Truthy : TypeFacts.Falsy));
|
||||
}
|
||||
if (containsMatchingReferenceDiscriminant(reference, expr)) {
|
||||
return declaredType;
|
||||
|
@ -14740,10 +14763,10 @@ namespace ts {
|
|||
return narrowTypeByEquality(type, operator, left, assumeTrue);
|
||||
}
|
||||
if (isMatchingReferenceDiscriminant(left, declaredType)) {
|
||||
return narrowTypeByDiscriminant(type, <PropertyAccessExpression>left, t => narrowTypeByEquality(t, operator, right, assumeTrue));
|
||||
return narrowTypeByDiscriminant(type, <PropertyAccessExpression | ElementAccessExpression>left, t => narrowTypeByEquality(t, operator, right, assumeTrue));
|
||||
}
|
||||
if (isMatchingReferenceDiscriminant(right, declaredType)) {
|
||||
return narrowTypeByDiscriminant(type, <PropertyAccessExpression>right, t => narrowTypeByEquality(t, operator, left, assumeTrue));
|
||||
return narrowTypeByDiscriminant(type, <PropertyAccessExpression | ElementAccessExpression>right, t => narrowTypeByEquality(t, operator, left, assumeTrue));
|
||||
}
|
||||
if (containsMatchingReferenceDiscriminant(reference, left) || containsMatchingReferenceDiscriminant(reference, right)) {
|
||||
return declaredType;
|
||||
|
@ -14982,6 +15005,7 @@ namespace ts {
|
|||
case SyntaxKind.ThisKeyword:
|
||||
case SyntaxKind.SuperKeyword:
|
||||
case SyntaxKind.PropertyAccessExpression:
|
||||
case SyntaxKind.ElementAccessExpression:
|
||||
return narrowTypeByTruthiness(type, expr, assumeTrue);
|
||||
case SyntaxKind.CallExpression:
|
||||
return narrowTypeByTypePredicate(type, <CallExpression>expr, assumeTrue);
|
||||
|
|
|
@ -135,9 +135,9 @@ M["x"] = 0;
|
|||
var a = M.x + 1;
|
||||
>a : number
|
||||
>M.x + 1 : number
|
||||
>M.x : number
|
||||
>M.x : 0
|
||||
>M : typeof M
|
||||
>x : number
|
||||
>x : 0
|
||||
>1 : 1
|
||||
|
||||
function f(v: number) { }
|
||||
|
@ -147,43 +147,43 @@ function f(v: number) { }
|
|||
f(M.x);
|
||||
>f(M.x) : void
|
||||
>f : (v: number) => void
|
||||
>M.x : number
|
||||
>M.x : 0
|
||||
>M : typeof M
|
||||
>x : number
|
||||
>x : 0
|
||||
|
||||
if (M.x) { }
|
||||
>M.x : number
|
||||
>M.x : 0
|
||||
>M : typeof M
|
||||
>x : number
|
||||
>x : 0
|
||||
|
||||
M.x;
|
||||
>M.x : number
|
||||
>M.x : 0
|
||||
>M : typeof M
|
||||
>x : number
|
||||
>x : 0
|
||||
|
||||
(M.x);
|
||||
>(M.x) : number
|
||||
>M.x : number
|
||||
>(M.x) : 0
|
||||
>M.x : 0
|
||||
>M : typeof M
|
||||
>x : number
|
||||
>x : 0
|
||||
|
||||
-M.x;
|
||||
>-M.x : number
|
||||
>M.x : number
|
||||
>M.x : 0
|
||||
>M : typeof M
|
||||
>x : number
|
||||
>x : 0
|
||||
|
||||
+M.x;
|
||||
>+M.x : number
|
||||
>M.x : number
|
||||
>M.x : 0
|
||||
>M : typeof M
|
||||
>x : number
|
||||
>x : 0
|
||||
|
||||
M.x.toString();
|
||||
>M.x.toString() : string
|
||||
>M.x.toString : (radix?: number) => string
|
||||
>M.x : number
|
||||
>M.x : 0
|
||||
>M : typeof M
|
||||
>x : number
|
||||
>x : 0
|
||||
>toString : (radix?: number) => string
|
||||
|
||||
|
|
|
@ -134,9 +134,9 @@ m["x"] = 0;
|
|||
var a = m.x + 1;
|
||||
>a : number
|
||||
>m.x + 1 : number
|
||||
>m.x : number
|
||||
>m.x : 0
|
||||
>m : typeof m
|
||||
>x : number
|
||||
>x : 0
|
||||
>1 : 1
|
||||
|
||||
function f(v: number) { }
|
||||
|
@ -146,44 +146,44 @@ function f(v: number) { }
|
|||
f(m.x);
|
||||
>f(m.x) : void
|
||||
>f : (v: number) => void
|
||||
>m.x : number
|
||||
>m.x : 0
|
||||
>m : typeof m
|
||||
>x : number
|
||||
>x : 0
|
||||
|
||||
if (m.x) { }
|
||||
>m.x : number
|
||||
>m.x : 0
|
||||
>m : typeof m
|
||||
>x : number
|
||||
>x : 0
|
||||
|
||||
m.x;
|
||||
>m.x : number
|
||||
>m.x : 0
|
||||
>m : typeof m
|
||||
>x : number
|
||||
>x : 0
|
||||
|
||||
(m.x);
|
||||
>(m.x) : number
|
||||
>m.x : number
|
||||
>(m.x) : 0
|
||||
>m.x : 0
|
||||
>m : typeof m
|
||||
>x : number
|
||||
>x : 0
|
||||
|
||||
-m.x;
|
||||
>-m.x : number
|
||||
>m.x : number
|
||||
>m.x : 0
|
||||
>m : typeof m
|
||||
>x : number
|
||||
>x : 0
|
||||
|
||||
+m.x;
|
||||
>+m.x : number
|
||||
>m.x : number
|
||||
>m.x : 0
|
||||
>m : typeof m
|
||||
>x : number
|
||||
>x : 0
|
||||
|
||||
m.x.toString();
|
||||
>m.x.toString() : string
|
||||
>m.x.toString : (radix?: number) => string
|
||||
>m.x : number
|
||||
>m.x : 0
|
||||
>m : typeof m
|
||||
>x : number
|
||||
>x : 0
|
||||
>toString : (radix?: number) => string
|
||||
|
||||
=== tests/cases/compiler/constDeclarations_access_1.ts ===
|
||||
|
|
|
@ -0,0 +1,123 @@
|
|||
//// [typeGuardNarrowsIndexedAccessOfKnownProperty.ts]
|
||||
interface Square {
|
||||
["dash-ok"]: "square";
|
||||
["square-size"]: number;
|
||||
}
|
||||
interface Rectangle {
|
||||
["dash-ok"]: "rectangle";
|
||||
width: number;
|
||||
height: number;
|
||||
}
|
||||
interface Circle {
|
||||
["dash-ok"]: "circle";
|
||||
radius: number;
|
||||
}
|
||||
type Shape = Square | Rectangle | Circle;
|
||||
interface Subshape {
|
||||
"0": {
|
||||
sub: {
|
||||
under: {
|
||||
shape: Shape;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
function area(s: Shape): number {
|
||||
switch(s['dash-ok']) {
|
||||
case "square": return s['square-size'] * s['square-size'];
|
||||
case "rectangle": return s.width * s['height'];
|
||||
case "circle": return Math.PI * s['radius'] * s.radius;
|
||||
}
|
||||
}
|
||||
function subarea(s: Subshape): number {
|
||||
switch(s[0]["sub"].under["shape"]["dash-ok"]) {
|
||||
case "square": return s[0].sub.under.shape["square-size"] * s[0].sub.under.shape["square-size"];
|
||||
case "rectangle": return s[0]["sub"]["under"]["shape"]["width"] * s[0]["sub"]["under"]["shape"].height;
|
||||
case "circle": return Math.PI * s[0].sub.under["shape"].radius * s[0]["sub"].under.shape["radius"];
|
||||
}
|
||||
}
|
||||
|
||||
interface X {
|
||||
0: "xx",
|
||||
1: number
|
||||
}
|
||||
|
||||
interface Y {
|
||||
0: "yy",
|
||||
1: string
|
||||
}
|
||||
|
||||
type A = ["aa", number];
|
||||
type B = ["bb", string];
|
||||
|
||||
type Z = X | Y;
|
||||
|
||||
type C = A | B;
|
||||
|
||||
function check(z: Z, c: C) {
|
||||
z[0] // fine, typescript sees "xx" | "yy"
|
||||
switch (z[0]) {
|
||||
case "xx":
|
||||
var xx: number = z[1] // should be number
|
||||
break;
|
||||
case "yy":
|
||||
var yy: string = z[1] // should be string
|
||||
break;
|
||||
}
|
||||
c[0] // fine, typescript sees "xx" | "yy"
|
||||
switch (c[0]) {
|
||||
case "aa":
|
||||
var aa: number = c[1] // should be number
|
||||
break;
|
||||
case "bb":
|
||||
var bb: string = c[1] // should be string
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
export function g(pair: [number, string?]): string {
|
||||
return pair[1] ? pair[1] : 'nope';
|
||||
}
|
||||
|
||||
|
||||
//// [typeGuardNarrowsIndexedAccessOfKnownProperty.js]
|
||||
"use strict";
|
||||
exports.__esModule = true;
|
||||
function area(s) {
|
||||
switch (s['dash-ok']) {
|
||||
case "square": return s['square-size'] * s['square-size'];
|
||||
case "rectangle": return s.width * s['height'];
|
||||
case "circle": return Math.PI * s['radius'] * s.radius;
|
||||
}
|
||||
}
|
||||
function subarea(s) {
|
||||
switch (s[0]["sub"].under["shape"]["dash-ok"]) {
|
||||
case "square": return s[0].sub.under.shape["square-size"] * s[0].sub.under.shape["square-size"];
|
||||
case "rectangle": return s[0]["sub"]["under"]["shape"]["width"] * s[0]["sub"]["under"]["shape"].height;
|
||||
case "circle": return Math.PI * s[0].sub.under["shape"].radius * s[0]["sub"].under.shape["radius"];
|
||||
}
|
||||
}
|
||||
function check(z, c) {
|
||||
z[0]; // fine, typescript sees "xx" | "yy"
|
||||
switch (z[0]) {
|
||||
case "xx":
|
||||
var xx = z[1]; // should be number
|
||||
break;
|
||||
case "yy":
|
||||
var yy = z[1]; // should be string
|
||||
break;
|
||||
}
|
||||
c[0]; // fine, typescript sees "xx" | "yy"
|
||||
switch (c[0]) {
|
||||
case "aa":
|
||||
var aa = c[1]; // should be number
|
||||
break;
|
||||
case "bb":
|
||||
var bb = c[1]; // should be string
|
||||
break;
|
||||
}
|
||||
}
|
||||
function g(pair) {
|
||||
return pair[1] ? pair[1] : 'nope';
|
||||
}
|
||||
exports.g = g;
|
|
@ -0,0 +1,268 @@
|
|||
=== tests/cases/compiler/typeGuardNarrowsIndexedAccessOfKnownProperty.ts ===
|
||||
interface Square {
|
||||
>Square : Symbol(Square, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 0, 0))
|
||||
|
||||
["dash-ok"]: "square";
|
||||
>["dash-ok"] : Symbol(Square["dash-ok"], Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 0, 18))
|
||||
>"dash-ok" : Symbol(Square["dash-ok"], Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 0, 18))
|
||||
|
||||
["square-size"]: number;
|
||||
>["square-size"] : Symbol(Square["square-size"], Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 1, 26))
|
||||
>"square-size" : Symbol(Square["square-size"], Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 1, 26))
|
||||
}
|
||||
interface Rectangle {
|
||||
>Rectangle : Symbol(Rectangle, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 3, 1))
|
||||
|
||||
["dash-ok"]: "rectangle";
|
||||
>["dash-ok"] : Symbol(Rectangle["dash-ok"], Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 4, 22))
|
||||
>"dash-ok" : Symbol(Rectangle["dash-ok"], Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 4, 22))
|
||||
|
||||
width: number;
|
||||
>width : Symbol(Rectangle.width, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 5, 29))
|
||||
|
||||
height: number;
|
||||
>height : Symbol(Rectangle.height, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 6, 18))
|
||||
}
|
||||
interface Circle {
|
||||
>Circle : Symbol(Circle, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 8, 1))
|
||||
|
||||
["dash-ok"]: "circle";
|
||||
>["dash-ok"] : Symbol(Circle["dash-ok"], Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 9, 19))
|
||||
>"dash-ok" : Symbol(Circle["dash-ok"], Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 9, 19))
|
||||
|
||||
radius: number;
|
||||
>radius : Symbol(Circle.radius, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 10, 26))
|
||||
}
|
||||
type Shape = Square | Rectangle | Circle;
|
||||
>Shape : Symbol(Shape, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 12, 1))
|
||||
>Square : Symbol(Square, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 0, 0))
|
||||
>Rectangle : Symbol(Rectangle, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 3, 1))
|
||||
>Circle : Symbol(Circle, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 8, 1))
|
||||
|
||||
interface Subshape {
|
||||
>Subshape : Symbol(Subshape, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 13, 42))
|
||||
|
||||
"0": {
|
||||
>"0" : Symbol(Subshape["0"], Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 14, 20))
|
||||
|
||||
sub: {
|
||||
>sub : Symbol(sub, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 15, 10))
|
||||
|
||||
under: {
|
||||
>under : Symbol(under, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 16, 14))
|
||||
|
||||
shape: Shape;
|
||||
>shape : Symbol(shape, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 17, 20))
|
||||
>Shape : Symbol(Shape, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 12, 1))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
function area(s: Shape): number {
|
||||
>area : Symbol(area, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 22, 1))
|
||||
>s : Symbol(s, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 23, 14))
|
||||
>Shape : Symbol(Shape, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 12, 1))
|
||||
|
||||
switch(s['dash-ok']) {
|
||||
>s : Symbol(s, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 23, 14))
|
||||
>'dash-ok' : Symbol(["dash-ok"], Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 0, 18), Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 4, 22), Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 9, 19))
|
||||
|
||||
case "square": return s['square-size'] * s['square-size'];
|
||||
>s : Symbol(s, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 23, 14))
|
||||
>'square-size' : Symbol(Square["square-size"], Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 1, 26))
|
||||
>s : Symbol(s, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 23, 14))
|
||||
>'square-size' : Symbol(Square["square-size"], Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 1, 26))
|
||||
|
||||
case "rectangle": return s.width * s['height'];
|
||||
>s.width : Symbol(Rectangle.width, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 5, 29))
|
||||
>s : Symbol(s, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 23, 14))
|
||||
>width : Symbol(Rectangle.width, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 5, 29))
|
||||
>s : Symbol(s, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 23, 14))
|
||||
>'height' : Symbol(Rectangle.height, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 6, 18))
|
||||
|
||||
case "circle": return Math.PI * s['radius'] * s.radius;
|
||||
>Math.PI : Symbol(Math.PI, Decl(lib.es5.d.ts, --, --))
|
||||
>Math : Symbol(Math, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
|
||||
>PI : Symbol(Math.PI, Decl(lib.es5.d.ts, --, --))
|
||||
>s : Symbol(s, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 23, 14))
|
||||
>'radius' : Symbol(Circle.radius, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 10, 26))
|
||||
>s.radius : Symbol(Circle.radius, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 10, 26))
|
||||
>s : Symbol(s, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 23, 14))
|
||||
>radius : Symbol(Circle.radius, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 10, 26))
|
||||
}
|
||||
}
|
||||
function subarea(s: Subshape): number {
|
||||
>subarea : Symbol(subarea, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 29, 1))
|
||||
>s : Symbol(s, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 30, 17))
|
||||
>Subshape : Symbol(Subshape, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 13, 42))
|
||||
|
||||
switch(s[0]["sub"].under["shape"]["dash-ok"]) {
|
||||
>s[0]["sub"].under : Symbol(under, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 16, 14))
|
||||
>s : Symbol(s, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 30, 17))
|
||||
>0 : Symbol(Subshape["0"], Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 14, 20))
|
||||
>"sub" : Symbol(sub, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 15, 10))
|
||||
>under : Symbol(under, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 16, 14))
|
||||
>"shape" : Symbol(shape, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 17, 20))
|
||||
>"dash-ok" : Symbol(["dash-ok"], Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 0, 18), Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 4, 22), Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 9, 19))
|
||||
|
||||
case "square": return s[0].sub.under.shape["square-size"] * s[0].sub.under.shape["square-size"];
|
||||
>s[0].sub.under.shape : Symbol(shape, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 17, 20))
|
||||
>s[0].sub.under : Symbol(under, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 16, 14))
|
||||
>s[0].sub : Symbol(sub, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 15, 10))
|
||||
>s : Symbol(s, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 30, 17))
|
||||
>0 : Symbol(Subshape["0"], Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 14, 20))
|
||||
>sub : Symbol(sub, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 15, 10))
|
||||
>under : Symbol(under, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 16, 14))
|
||||
>shape : Symbol(shape, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 17, 20))
|
||||
>"square-size" : Symbol(Square["square-size"], Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 1, 26))
|
||||
>s[0].sub.under.shape : Symbol(shape, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 17, 20))
|
||||
>s[0].sub.under : Symbol(under, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 16, 14))
|
||||
>s[0].sub : Symbol(sub, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 15, 10))
|
||||
>s : Symbol(s, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 30, 17))
|
||||
>0 : Symbol(Subshape["0"], Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 14, 20))
|
||||
>sub : Symbol(sub, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 15, 10))
|
||||
>under : Symbol(under, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 16, 14))
|
||||
>shape : Symbol(shape, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 17, 20))
|
||||
>"square-size" : Symbol(Square["square-size"], Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 1, 26))
|
||||
|
||||
case "rectangle": return s[0]["sub"]["under"]["shape"]["width"] * s[0]["sub"]["under"]["shape"].height;
|
||||
>s : Symbol(s, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 30, 17))
|
||||
>0 : Symbol(Subshape["0"], Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 14, 20))
|
||||
>"sub" : Symbol(sub, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 15, 10))
|
||||
>"under" : Symbol(under, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 16, 14))
|
||||
>"shape" : Symbol(shape, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 17, 20))
|
||||
>"width" : Symbol(Rectangle.width, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 5, 29))
|
||||
>s[0]["sub"]["under"]["shape"].height : Symbol(Rectangle.height, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 6, 18))
|
||||
>s : Symbol(s, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 30, 17))
|
||||
>0 : Symbol(Subshape["0"], Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 14, 20))
|
||||
>"sub" : Symbol(sub, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 15, 10))
|
||||
>"under" : Symbol(under, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 16, 14))
|
||||
>"shape" : Symbol(shape, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 17, 20))
|
||||
>height : Symbol(Rectangle.height, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 6, 18))
|
||||
|
||||
case "circle": return Math.PI * s[0].sub.under["shape"].radius * s[0]["sub"].under.shape["radius"];
|
||||
>Math.PI : Symbol(Math.PI, Decl(lib.es5.d.ts, --, --))
|
||||
>Math : Symbol(Math, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
|
||||
>PI : Symbol(Math.PI, Decl(lib.es5.d.ts, --, --))
|
||||
>s[0].sub.under["shape"].radius : Symbol(Circle.radius, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 10, 26))
|
||||
>s[0].sub.under : Symbol(under, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 16, 14))
|
||||
>s[0].sub : Symbol(sub, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 15, 10))
|
||||
>s : Symbol(s, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 30, 17))
|
||||
>0 : Symbol(Subshape["0"], Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 14, 20))
|
||||
>sub : Symbol(sub, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 15, 10))
|
||||
>under : Symbol(under, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 16, 14))
|
||||
>"shape" : Symbol(shape, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 17, 20))
|
||||
>radius : Symbol(Circle.radius, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 10, 26))
|
||||
>s[0]["sub"].under.shape : Symbol(shape, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 17, 20))
|
||||
>s[0]["sub"].under : Symbol(under, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 16, 14))
|
||||
>s : Symbol(s, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 30, 17))
|
||||
>0 : Symbol(Subshape["0"], Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 14, 20))
|
||||
>"sub" : Symbol(sub, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 15, 10))
|
||||
>under : Symbol(under, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 16, 14))
|
||||
>shape : Symbol(shape, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 17, 20))
|
||||
>"radius" : Symbol(Circle.radius, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 10, 26))
|
||||
}
|
||||
}
|
||||
|
||||
interface X {
|
||||
>X : Symbol(X, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 36, 1))
|
||||
|
||||
0: "xx",
|
||||
>0 : Symbol(X[0], Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 38, 13))
|
||||
|
||||
1: number
|
||||
>1 : Symbol(X[1], Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 39, 12))
|
||||
}
|
||||
|
||||
interface Y {
|
||||
>Y : Symbol(Y, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 41, 1))
|
||||
|
||||
0: "yy",
|
||||
>0 : Symbol(Y[0], Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 43, 13))
|
||||
|
||||
1: string
|
||||
>1 : Symbol(Y[1], Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 44, 12))
|
||||
}
|
||||
|
||||
type A = ["aa", number];
|
||||
>A : Symbol(A, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 46, 1))
|
||||
|
||||
type B = ["bb", string];
|
||||
>B : Symbol(B, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 48, 24))
|
||||
|
||||
type Z = X | Y;
|
||||
>Z : Symbol(Z, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 49, 24))
|
||||
>X : Symbol(X, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 36, 1))
|
||||
>Y : Symbol(Y, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 41, 1))
|
||||
|
||||
type C = A | B;
|
||||
>C : Symbol(C, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 51, 15))
|
||||
>A : Symbol(A, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 46, 1))
|
||||
>B : Symbol(B, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 48, 24))
|
||||
|
||||
function check(z: Z, c: C) {
|
||||
>check : Symbol(check, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 53, 15))
|
||||
>z : Symbol(z, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 55, 15))
|
||||
>Z : Symbol(Z, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 49, 24))
|
||||
>c : Symbol(c, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 55, 20))
|
||||
>C : Symbol(C, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 51, 15))
|
||||
|
||||
z[0] // fine, typescript sees "xx" | "yy"
|
||||
>z : Symbol(z, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 55, 15))
|
||||
>0 : Symbol(0, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 38, 13), Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 43, 13))
|
||||
|
||||
switch (z[0]) {
|
||||
>z : Symbol(z, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 55, 15))
|
||||
>0 : Symbol(0, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 38, 13), Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 43, 13))
|
||||
|
||||
case "xx":
|
||||
var xx: number = z[1] // should be number
|
||||
>xx : Symbol(xx, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 59, 15))
|
||||
>z : Symbol(z, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 55, 15))
|
||||
>1 : Symbol(X[1], Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 39, 12))
|
||||
|
||||
break;
|
||||
case "yy":
|
||||
var yy: string = z[1] // should be string
|
||||
>yy : Symbol(yy, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 62, 15))
|
||||
>z : Symbol(z, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 55, 15))
|
||||
>1 : Symbol(Y[1], Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 44, 12))
|
||||
|
||||
break;
|
||||
}
|
||||
c[0] // fine, typescript sees "xx" | "yy"
|
||||
>c : Symbol(c, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 55, 20))
|
||||
>0 : Symbol(0)
|
||||
|
||||
switch (c[0]) {
|
||||
>c : Symbol(c, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 55, 20))
|
||||
>0 : Symbol(0)
|
||||
|
||||
case "aa":
|
||||
var aa: number = c[1] // should be number
|
||||
>aa : Symbol(aa, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 68, 15))
|
||||
>c : Symbol(c, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 55, 20))
|
||||
>1 : Symbol(1)
|
||||
|
||||
break;
|
||||
case "bb":
|
||||
var bb: string = c[1] // should be string
|
||||
>bb : Symbol(bb, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 71, 15))
|
||||
>c : Symbol(c, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 55, 20))
|
||||
>1 : Symbol(1)
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
export function g(pair: [number, string?]): string {
|
||||
>g : Symbol(g, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 74, 1))
|
||||
>pair : Symbol(pair, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 76, 18))
|
||||
|
||||
return pair[1] ? pair[1] : 'nope';
|
||||
>pair : Symbol(pair, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 76, 18))
|
||||
>1 : Symbol(1)
|
||||
>pair : Symbol(pair, Decl(typeGuardNarrowsIndexedAccessOfKnownProperty.ts, 76, 18))
|
||||
>1 : Symbol(1)
|
||||
}
|
||||
|
|
@ -0,0 +1,305 @@
|
|||
=== tests/cases/compiler/typeGuardNarrowsIndexedAccessOfKnownProperty.ts ===
|
||||
interface Square {
|
||||
["dash-ok"]: "square";
|
||||
>["dash-ok"] : "square"
|
||||
>"dash-ok" : "dash-ok"
|
||||
|
||||
["square-size"]: number;
|
||||
>["square-size"] : number
|
||||
>"square-size" : "square-size"
|
||||
}
|
||||
interface Rectangle {
|
||||
["dash-ok"]: "rectangle";
|
||||
>["dash-ok"] : "rectangle"
|
||||
>"dash-ok" : "dash-ok"
|
||||
|
||||
width: number;
|
||||
>width : number
|
||||
|
||||
height: number;
|
||||
>height : number
|
||||
}
|
||||
interface Circle {
|
||||
["dash-ok"]: "circle";
|
||||
>["dash-ok"] : "circle"
|
||||
>"dash-ok" : "dash-ok"
|
||||
|
||||
radius: number;
|
||||
>radius : number
|
||||
}
|
||||
type Shape = Square | Rectangle | Circle;
|
||||
>Shape : Shape
|
||||
|
||||
interface Subshape {
|
||||
"0": {
|
||||
>"0" : { sub: { under: { shape: Shape; }; }; }
|
||||
|
||||
sub: {
|
||||
>sub : { under: { shape: Shape; }; }
|
||||
|
||||
under: {
|
||||
>under : { shape: Shape; }
|
||||
|
||||
shape: Shape;
|
||||
>shape : Shape
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
function area(s: Shape): number {
|
||||
>area : (s: Shape) => number
|
||||
>s : Shape
|
||||
|
||||
switch(s['dash-ok']) {
|
||||
>s['dash-ok'] : "square" | "rectangle" | "circle"
|
||||
>s : Shape
|
||||
>'dash-ok' : "dash-ok"
|
||||
|
||||
case "square": return s['square-size'] * s['square-size'];
|
||||
>"square" : "square"
|
||||
>s['square-size'] * s['square-size'] : number
|
||||
>s['square-size'] : number
|
||||
>s : Square
|
||||
>'square-size' : "square-size"
|
||||
>s['square-size'] : number
|
||||
>s : Square
|
||||
>'square-size' : "square-size"
|
||||
|
||||
case "rectangle": return s.width * s['height'];
|
||||
>"rectangle" : "rectangle"
|
||||
>s.width * s['height'] : number
|
||||
>s.width : number
|
||||
>s : Rectangle
|
||||
>width : number
|
||||
>s['height'] : number
|
||||
>s : Rectangle
|
||||
>'height' : "height"
|
||||
|
||||
case "circle": return Math.PI * s['radius'] * s.radius;
|
||||
>"circle" : "circle"
|
||||
>Math.PI * s['radius'] * s.radius : number
|
||||
>Math.PI * s['radius'] : number
|
||||
>Math.PI : number
|
||||
>Math : Math
|
||||
>PI : number
|
||||
>s['radius'] : number
|
||||
>s : Circle
|
||||
>'radius' : "radius"
|
||||
>s.radius : number
|
||||
>s : Circle
|
||||
>radius : number
|
||||
}
|
||||
}
|
||||
function subarea(s: Subshape): number {
|
||||
>subarea : (s: Subshape) => number
|
||||
>s : Subshape
|
||||
|
||||
switch(s[0]["sub"].under["shape"]["dash-ok"]) {
|
||||
>s[0]["sub"].under["shape"]["dash-ok"] : "square" | "rectangle" | "circle"
|
||||
>s[0]["sub"].under["shape"] : Shape
|
||||
>s[0]["sub"].under : { shape: Shape; }
|
||||
>s[0]["sub"] : { under: { shape: Shape; }; }
|
||||
>s[0] : { sub: { under: { shape: Shape; }; }; }
|
||||
>s : Subshape
|
||||
>0 : 0
|
||||
>"sub" : "sub"
|
||||
>under : { shape: Shape; }
|
||||
>"shape" : "shape"
|
||||
>"dash-ok" : "dash-ok"
|
||||
|
||||
case "square": return s[0].sub.under.shape["square-size"] * s[0].sub.under.shape["square-size"];
|
||||
>"square" : "square"
|
||||
>s[0].sub.under.shape["square-size"] * s[0].sub.under.shape["square-size"] : number
|
||||
>s[0].sub.under.shape["square-size"] : number
|
||||
>s[0].sub.under.shape : Square
|
||||
>s[0].sub.under : { shape: Shape; }
|
||||
>s[0].sub : { under: { shape: Shape; }; }
|
||||
>s[0] : { sub: { under: { shape: Shape; }; }; }
|
||||
>s : Subshape
|
||||
>0 : 0
|
||||
>sub : { under: { shape: Shape; }; }
|
||||
>under : { shape: Shape; }
|
||||
>shape : Square
|
||||
>"square-size" : "square-size"
|
||||
>s[0].sub.under.shape["square-size"] : number
|
||||
>s[0].sub.under.shape : Square
|
||||
>s[0].sub.under : { shape: Shape; }
|
||||
>s[0].sub : { under: { shape: Shape; }; }
|
||||
>s[0] : { sub: { under: { shape: Shape; }; }; }
|
||||
>s : Subshape
|
||||
>0 : 0
|
||||
>sub : { under: { shape: Shape; }; }
|
||||
>under : { shape: Shape; }
|
||||
>shape : Square
|
||||
>"square-size" : "square-size"
|
||||
|
||||
case "rectangle": return s[0]["sub"]["under"]["shape"]["width"] * s[0]["sub"]["under"]["shape"].height;
|
||||
>"rectangle" : "rectangle"
|
||||
>s[0]["sub"]["under"]["shape"]["width"] * s[0]["sub"]["under"]["shape"].height : number
|
||||
>s[0]["sub"]["under"]["shape"]["width"] : number
|
||||
>s[0]["sub"]["under"]["shape"] : Rectangle
|
||||
>s[0]["sub"]["under"] : { shape: Shape; }
|
||||
>s[0]["sub"] : { under: { shape: Shape; }; }
|
||||
>s[0] : { sub: { under: { shape: Shape; }; }; }
|
||||
>s : Subshape
|
||||
>0 : 0
|
||||
>"sub" : "sub"
|
||||
>"under" : "under"
|
||||
>"shape" : "shape"
|
||||
>"width" : "width"
|
||||
>s[0]["sub"]["under"]["shape"].height : number
|
||||
>s[0]["sub"]["under"]["shape"] : Rectangle
|
||||
>s[0]["sub"]["under"] : { shape: Shape; }
|
||||
>s[0]["sub"] : { under: { shape: Shape; }; }
|
||||
>s[0] : { sub: { under: { shape: Shape; }; }; }
|
||||
>s : Subshape
|
||||
>0 : 0
|
||||
>"sub" : "sub"
|
||||
>"under" : "under"
|
||||
>"shape" : "shape"
|
||||
>height : number
|
||||
|
||||
case "circle": return Math.PI * s[0].sub.under["shape"].radius * s[0]["sub"].under.shape["radius"];
|
||||
>"circle" : "circle"
|
||||
>Math.PI * s[0].sub.under["shape"].radius * s[0]["sub"].under.shape["radius"] : number
|
||||
>Math.PI * s[0].sub.under["shape"].radius : number
|
||||
>Math.PI : number
|
||||
>Math : Math
|
||||
>PI : number
|
||||
>s[0].sub.under["shape"].radius : number
|
||||
>s[0].sub.under["shape"] : Circle
|
||||
>s[0].sub.under : { shape: Shape; }
|
||||
>s[0].sub : { under: { shape: Shape; }; }
|
||||
>s[0] : { sub: { under: { shape: Shape; }; }; }
|
||||
>s : Subshape
|
||||
>0 : 0
|
||||
>sub : { under: { shape: Shape; }; }
|
||||
>under : { shape: Shape; }
|
||||
>"shape" : "shape"
|
||||
>radius : number
|
||||
>s[0]["sub"].under.shape["radius"] : number
|
||||
>s[0]["sub"].under.shape : Circle
|
||||
>s[0]["sub"].under : { shape: Shape; }
|
||||
>s[0]["sub"] : { under: { shape: Shape; }; }
|
||||
>s[0] : { sub: { under: { shape: Shape; }; }; }
|
||||
>s : Subshape
|
||||
>0 : 0
|
||||
>"sub" : "sub"
|
||||
>under : { shape: Shape; }
|
||||
>shape : Circle
|
||||
>"radius" : "radius"
|
||||
}
|
||||
}
|
||||
|
||||
interface X {
|
||||
0: "xx",
|
||||
>0 : "xx"
|
||||
|
||||
1: number
|
||||
>1 : number
|
||||
}
|
||||
|
||||
interface Y {
|
||||
0: "yy",
|
||||
>0 : "yy"
|
||||
|
||||
1: string
|
||||
>1 : string
|
||||
}
|
||||
|
||||
type A = ["aa", number];
|
||||
>A : ["aa", number]
|
||||
|
||||
type B = ["bb", string];
|
||||
>B : ["bb", string]
|
||||
|
||||
type Z = X | Y;
|
||||
>Z : Z
|
||||
|
||||
type C = A | B;
|
||||
>C : C
|
||||
|
||||
function check(z: Z, c: C) {
|
||||
>check : (z: Z, c: C) => void
|
||||
>z : Z
|
||||
>c : C
|
||||
|
||||
z[0] // fine, typescript sees "xx" | "yy"
|
||||
>z[0] : "xx" | "yy"
|
||||
>z : Z
|
||||
>0 : 0
|
||||
|
||||
switch (z[0]) {
|
||||
>z[0] : "xx" | "yy"
|
||||
>z : Z
|
||||
>0 : 0
|
||||
|
||||
case "xx":
|
||||
>"xx" : "xx"
|
||||
|
||||
var xx: number = z[1] // should be number
|
||||
>xx : number
|
||||
>z[1] : number
|
||||
>z : X
|
||||
>1 : 1
|
||||
|
||||
break;
|
||||
case "yy":
|
||||
>"yy" : "yy"
|
||||
|
||||
var yy: string = z[1] // should be string
|
||||
>yy : string
|
||||
>z[1] : string
|
||||
>z : Y
|
||||
>1 : 1
|
||||
|
||||
break;
|
||||
}
|
||||
c[0] // fine, typescript sees "xx" | "yy"
|
||||
>c[0] : "aa" | "bb"
|
||||
>c : C
|
||||
>0 : 0
|
||||
|
||||
switch (c[0]) {
|
||||
>c[0] : "aa" | "bb"
|
||||
>c : C
|
||||
>0 : 0
|
||||
|
||||
case "aa":
|
||||
>"aa" : "aa"
|
||||
|
||||
var aa: number = c[1] // should be number
|
||||
>aa : number
|
||||
>c[1] : number
|
||||
>c : ["aa", number]
|
||||
>1 : 1
|
||||
|
||||
break;
|
||||
case "bb":
|
||||
>"bb" : "bb"
|
||||
|
||||
var bb: string = c[1] // should be string
|
||||
>bb : string
|
||||
>c[1] : string
|
||||
>c : ["bb", string]
|
||||
>1 : 1
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
export function g(pair: [number, string?]): string {
|
||||
>g : (pair: [number, (string | undefined)?]) => string
|
||||
>pair : [number, (string | undefined)?]
|
||||
|
||||
return pair[1] ? pair[1] : 'nope';
|
||||
>pair[1] ? pair[1] : 'nope' : string
|
||||
>pair[1] : string | undefined
|
||||
>pair : [number, (string | undefined)?]
|
||||
>1 : 1
|
||||
>pair[1] : string
|
||||
>pair : [number, (string | undefined)?]
|
||||
>1 : 1
|
||||
>'nope' : "nope"
|
||||
}
|
||||
|
|
@ -1,12 +1,13 @@
|
|||
tests/cases/conformance/types/union/unionTypeWithIndexSignature.ts(11,3): error TS2339: Property 'bar' does not exist on type 'Missing'.
|
||||
Property 'bar' does not exist on type '{ [s: string]: string; }'.
|
||||
tests/cases/conformance/types/union/unionTypeWithIndexSignature.ts(14,4): error TS2540: Cannot assign to 'foo' because it is a constant or a read-only property.
|
||||
tests/cases/conformance/types/union/unionTypeWithIndexSignature.ts(18,1): error TS2322: Type '"ok"' is not assignable to type 'number'.
|
||||
tests/cases/conformance/types/union/unionTypeWithIndexSignature.ts(24,1): error TS7017: Element implicitly has an 'any' type because type 'Both' has no index signature.
|
||||
tests/cases/conformance/types/union/unionTypeWithIndexSignature.ts(25,1): error TS2322: Type '"not ok"' is not assignable to type 'number'.
|
||||
tests/cases/conformance/types/union/unionTypeWithIndexSignature.ts(26,1): error TS7017: Element implicitly has an 'any' type because type 'Both' has no index signature.
|
||||
|
||||
|
||||
==== tests/cases/conformance/types/union/unionTypeWithIndexSignature.ts (5 errors) ====
|
||||
==== tests/cases/conformance/types/union/unionTypeWithIndexSignature.ts (6 errors) ====
|
||||
type Two = { foo: { bar: true }, baz: true } | { [s: string]: string };
|
||||
declare var u: Two
|
||||
u.foo = 'bye'
|
||||
|
@ -30,6 +31,8 @@ tests/cases/conformance/types/union/unionTypeWithIndexSignature.ts(26,1): error
|
|||
declare var num: Num
|
||||
num[0] = 1
|
||||
num['0'] = 'ok'
|
||||
~~~~~~~~
|
||||
!!! error TS2322: Type '"ok"' is not assignable to type 'number'.
|
||||
const sym = Symbol()
|
||||
type Both = { s: number, '0': number, [sym]: boolean } | { [n: number]: number, [s: string]: string | number }
|
||||
declare var both: Both
|
||||
|
|
|
@ -96,7 +96,7 @@ num[0] = 1
|
|||
|
||||
num['0'] = 'ok'
|
||||
>num['0'] = 'ok' : "ok"
|
||||
>num['0'] : string | number
|
||||
>num['0'] : number
|
||||
>num : Num
|
||||
>'0' : "0"
|
||||
>'ok' : "ok"
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
// @strict: true
|
||||
interface Square {
|
||||
["dash-ok"]: "square";
|
||||
["square-size"]: number;
|
||||
}
|
||||
interface Rectangle {
|
||||
["dash-ok"]: "rectangle";
|
||||
width: number;
|
||||
height: number;
|
||||
}
|
||||
interface Circle {
|
||||
["dash-ok"]: "circle";
|
||||
radius: number;
|
||||
}
|
||||
type Shape = Square | Rectangle | Circle;
|
||||
interface Subshape {
|
||||
"0": {
|
||||
sub: {
|
||||
under: {
|
||||
shape: Shape;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
function area(s: Shape): number {
|
||||
switch(s['dash-ok']) {
|
||||
case "square": return s['square-size'] * s['square-size'];
|
||||
case "rectangle": return s.width * s['height'];
|
||||
case "circle": return Math.PI * s['radius'] * s.radius;
|
||||
}
|
||||
}
|
||||
function subarea(s: Subshape): number {
|
||||
switch(s[0]["sub"].under["shape"]["dash-ok"]) {
|
||||
case "square": return s[0].sub.under.shape["square-size"] * s[0].sub.under.shape["square-size"];
|
||||
case "rectangle": return s[0]["sub"]["under"]["shape"]["width"] * s[0]["sub"]["under"]["shape"].height;
|
||||
case "circle": return Math.PI * s[0].sub.under["shape"].radius * s[0]["sub"].under.shape["radius"];
|
||||
}
|
||||
}
|
||||
|
||||
interface X {
|
||||
0: "xx",
|
||||
1: number
|
||||
}
|
||||
|
||||
interface Y {
|
||||
0: "yy",
|
||||
1: string
|
||||
}
|
||||
|
||||
type A = ["aa", number];
|
||||
type B = ["bb", string];
|
||||
|
||||
type Z = X | Y;
|
||||
|
||||
type C = A | B;
|
||||
|
||||
function check(z: Z, c: C) {
|
||||
z[0] // fine, typescript sees "xx" | "yy"
|
||||
switch (z[0]) {
|
||||
case "xx":
|
||||
var xx: number = z[1] // should be number
|
||||
break;
|
||||
case "yy":
|
||||
var yy: string = z[1] // should be string
|
||||
break;
|
||||
}
|
||||
c[0] // fine, typescript sees "xx" | "yy"
|
||||
switch (c[0]) {
|
||||
case "aa":
|
||||
var aa: number = c[1] // should be number
|
||||
break;
|
||||
case "bb":
|
||||
var bb: string = c[1] // should be string
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
export function g(pair: [number, string?]): string {
|
||||
return pair[1] ? pair[1] : 'nope';
|
||||
}
|
Loading…
Reference in a new issue