mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
support generic type when checking implicit conversion of symbol to string (#44578)
Co-authored-by: Wesley Wigham <wewigham@microsoft.com>
This commit is contained in:
+13
-4
@@ -32810,7 +32810,7 @@ namespace ts {
|
||||
case SyntaxKind.MinusToken:
|
||||
case SyntaxKind.TildeToken:
|
||||
checkNonNullType(operandType, node.operand);
|
||||
if (maybeTypeOfKind(operandType, TypeFlags.ESSymbolLike)) {
|
||||
if (maybeTypeOfKindConsideringBaseConstraint(operandType, TypeFlags.ESSymbolLike)) {
|
||||
error(node.operand, Diagnostics.The_0_operator_cannot_be_applied_to_type_symbol, tokenToString(node.operator));
|
||||
}
|
||||
if (node.operator === SyntaxKind.PlusToken) {
|
||||
@@ -32871,6 +32871,15 @@ namespace ts {
|
||||
return numberType;
|
||||
}
|
||||
|
||||
function maybeTypeOfKindConsideringBaseConstraint(type: Type, kind: TypeFlags): boolean {
|
||||
if (maybeTypeOfKind(type, kind)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const baseConstraint = getBaseConstraintOrType(type);
|
||||
return !!baseConstraint && maybeTypeOfKind(baseConstraint, kind);
|
||||
}
|
||||
|
||||
// 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 {
|
||||
@@ -33654,8 +33663,8 @@ namespace ts {
|
||||
// Return true if there was no error, false if there was an error.
|
||||
function checkForDisallowedESSymbolOperand(operator: SyntaxKind): boolean {
|
||||
const offendingSymbolOperand =
|
||||
maybeTypeOfKind(leftType, TypeFlags.ESSymbolLike) ? left :
|
||||
maybeTypeOfKind(rightType, TypeFlags.ESSymbolLike) ? right :
|
||||
maybeTypeOfKindConsideringBaseConstraint(leftType, TypeFlags.ESSymbolLike) ? left :
|
||||
maybeTypeOfKindConsideringBaseConstraint(rightType, TypeFlags.ESSymbolLike) ? right :
|
||||
undefined;
|
||||
|
||||
if (offendingSymbolOperand) {
|
||||
@@ -33893,7 +33902,7 @@ namespace ts {
|
||||
const types = [];
|
||||
for (const span of node.templateSpans) {
|
||||
const type = checkExpression(span.expression);
|
||||
if (maybeTypeOfKind(type, TypeFlags.ESSymbolLike)) {
|
||||
if (maybeTypeOfKindConsideringBaseConstraint(type, TypeFlags.ESSymbolLike)) {
|
||||
error(span.expression, Diagnostics.Implicit_conversion_of_a_symbol_to_a_string_will_fail_at_runtime_Consider_wrapping_this_expression_in_String);
|
||||
}
|
||||
texts.push(span.literal.text);
|
||||
|
||||
@@ -3,9 +3,19 @@ tests/cases/compiler/noImplicitSymbolToString.ts(7,30): error TS2469: The '+' op
|
||||
tests/cases/compiler/noImplicitSymbolToString.ts(8,8): error TS2469: The '+=' operator cannot be applied to type 'symbol'.
|
||||
tests/cases/compiler/noImplicitSymbolToString.ts(13,47): error TS2731: Implicit conversion of a 'symbol' to a 'string' will fail at runtime. Consider wrapping this expression in 'String(...)'.
|
||||
tests/cases/compiler/noImplicitSymbolToString.ts(13,90): error TS2731: Implicit conversion of a 'symbol' to a 'string' will fail at runtime. Consider wrapping this expression in 'String(...)'.
|
||||
tests/cases/compiler/noImplicitSymbolToString.ts(21,15): error TS2731: Implicit conversion of a 'symbol' to a 'string' will fail at runtime. Consider wrapping this expression in 'String(...)'.
|
||||
tests/cases/compiler/noImplicitSymbolToString.ts(26,8): error TS2731: Implicit conversion of a 'symbol' to a 'string' will fail at runtime. Consider wrapping this expression in 'String(...)'.
|
||||
tests/cases/compiler/noImplicitSymbolToString.ts(27,5): error TS2469: The '+' operator cannot be applied to type 'symbol'.
|
||||
tests/cases/compiler/noImplicitSymbolToString.ts(28,6): error TS2469: The '+' operator cannot be applied to type 'symbol'.
|
||||
tests/cases/compiler/noImplicitSymbolToString.ts(31,8): error TS2731: Implicit conversion of a 'symbol' to a 'string' will fail at runtime. Consider wrapping this expression in 'String(...)'.
|
||||
tests/cases/compiler/noImplicitSymbolToString.ts(32,5): error TS2469: The '+' operator cannot be applied to type 'symbol'.
|
||||
tests/cases/compiler/noImplicitSymbolToString.ts(33,6): error TS2469: The '+' operator cannot be applied to type 'symbol'.
|
||||
tests/cases/compiler/noImplicitSymbolToString.ts(43,8): error TS2731: Implicit conversion of a 'symbol' to a 'string' will fail at runtime. Consider wrapping this expression in 'String(...)'.
|
||||
tests/cases/compiler/noImplicitSymbolToString.ts(44,5): error TS2469: The '+' operator cannot be applied to type 'symbol'.
|
||||
tests/cases/compiler/noImplicitSymbolToString.ts(45,6): error TS2469: The '+' operator cannot be applied to type 'symbol'.
|
||||
|
||||
|
||||
==== tests/cases/compiler/noImplicitSymbolToString.ts (5 errors) ====
|
||||
==== tests/cases/compiler/noImplicitSymbolToString.ts (15 errors) ====
|
||||
// Fix #19666
|
||||
|
||||
let symbol!: symbol;
|
||||
@@ -29,4 +39,57 @@ tests/cases/compiler/noImplicitSymbolToString.ts(13,90): error TS2731: Implicit
|
||||
!!! error TS2731: Implicit conversion of a 'symbol' to a 'string' will fail at runtime. Consider wrapping this expression in 'String(...)'.
|
||||
~~~~~~~~~~~~~~~~~
|
||||
!!! error TS2731: Implicit conversion of a 'symbol' to a 'string' will fail at runtime. Consider wrapping this expression in 'String(...)'.
|
||||
|
||||
|
||||
// Fix #44462
|
||||
|
||||
type StringOrSymbol = string | symbol;
|
||||
|
||||
function getKey<S extends StringOrSymbol>(key: S) {
|
||||
return `${key} is the key`;
|
||||
~~~
|
||||
!!! error TS2731: Implicit conversion of a 'symbol' to a 'string' will fail at runtime. Consider wrapping this expression in 'String(...)'.
|
||||
}
|
||||
|
||||
function getKey1<S extends symbol>(key: S) {
|
||||
let s1!: S;
|
||||
`${s1}`;
|
||||
~~
|
||||
!!! error TS2731: Implicit conversion of a 'symbol' to a 'string' will fail at runtime. Consider wrapping this expression in 'String(...)'.
|
||||
s1 + '';
|
||||
~~
|
||||
!!! error TS2469: The '+' operator cannot be applied to type 'symbol'.
|
||||
+s1;
|
||||
~~
|
||||
!!! error TS2469: The '+' operator cannot be applied to type 'symbol'.
|
||||
|
||||
let s2!: S | string;
|
||||
`${s2}`;
|
||||
~~
|
||||
!!! error TS2731: Implicit conversion of a 'symbol' to a 'string' will fail at runtime. Consider wrapping this expression in 'String(...)'.
|
||||
s2 + '';
|
||||
~~
|
||||
!!! error TS2469: The '+' operator cannot be applied to type 'symbol'.
|
||||
+s2;
|
||||
~~
|
||||
!!! error TS2469: The '+' operator cannot be applied to type 'symbol'.
|
||||
}
|
||||
|
||||
function getKey2<S extends string>(key: S) {
|
||||
let s1!: S;
|
||||
`${s1}`;
|
||||
s1 + '';
|
||||
+s1;
|
||||
|
||||
let s2!: S | symbol;
|
||||
`${s2}`;
|
||||
~~
|
||||
!!! error TS2731: Implicit conversion of a 'symbol' to a 'string' will fail at runtime. Consider wrapping this expression in 'String(...)'.
|
||||
s2 + '';
|
||||
~~
|
||||
!!! error TS2469: The '+' operator cannot be applied to type 'symbol'.
|
||||
+s2;
|
||||
~~
|
||||
!!! error TS2469: The '+' operator cannot be applied to type 'symbol'.
|
||||
}
|
||||
|
||||
@@ -12,6 +12,39 @@ let symbolUnionNumber!: symbol | number;
|
||||
let symbolUnionString!: symbol | string;
|
||||
|
||||
const templateStrUnion = `union with number ${symbolUnionNumber} and union with string ${symbolUnionString}`;
|
||||
|
||||
|
||||
// Fix #44462
|
||||
|
||||
type StringOrSymbol = string | symbol;
|
||||
|
||||
function getKey<S extends StringOrSymbol>(key: S) {
|
||||
return `${key} is the key`;
|
||||
}
|
||||
|
||||
function getKey1<S extends symbol>(key: S) {
|
||||
let s1!: S;
|
||||
`${s1}`;
|
||||
s1 + '';
|
||||
+s1;
|
||||
|
||||
let s2!: S | string;
|
||||
`${s2}`;
|
||||
s2 + '';
|
||||
+s2;
|
||||
}
|
||||
|
||||
function getKey2<S extends string>(key: S) {
|
||||
let s1!: S;
|
||||
`${s1}`;
|
||||
s1 + '';
|
||||
+s1;
|
||||
|
||||
let s2!: S | symbol;
|
||||
`${s2}`;
|
||||
s2 + '';
|
||||
+s2;
|
||||
}
|
||||
|
||||
|
||||
//// [noImplicitSymbolToString.js]
|
||||
@@ -24,3 +57,26 @@ str += symbol;
|
||||
var symbolUnionNumber;
|
||||
var symbolUnionString;
|
||||
var templateStrUnion = "union with number ".concat(symbolUnionNumber, " and union with string ").concat(symbolUnionString);
|
||||
function getKey(key) {
|
||||
return "".concat(key, " is the key");
|
||||
}
|
||||
function getKey1(key) {
|
||||
var s1;
|
||||
"".concat(s1);
|
||||
s1 + '';
|
||||
+s1;
|
||||
var s2;
|
||||
"".concat(s2);
|
||||
s2 + '';
|
||||
+s2;
|
||||
}
|
||||
function getKey2(key) {
|
||||
var s1;
|
||||
"".concat(s1);
|
||||
s1 + '';
|
||||
+s1;
|
||||
var s2;
|
||||
"".concat(s2);
|
||||
s2 + '';
|
||||
+s2;
|
||||
}
|
||||
|
||||
@@ -30,3 +30,86 @@ const templateStrUnion = `union with number ${symbolUnionNumber} and union with
|
||||
>symbolUnionNumber : Symbol(symbolUnionNumber, Decl(noImplicitSymbolToString.ts, 9, 3))
|
||||
>symbolUnionString : Symbol(symbolUnionString, Decl(noImplicitSymbolToString.ts, 10, 3))
|
||||
|
||||
|
||||
// Fix #44462
|
||||
|
||||
type StringOrSymbol = string | symbol;
|
||||
>StringOrSymbol : Symbol(StringOrSymbol, Decl(noImplicitSymbolToString.ts, 12, 109))
|
||||
|
||||
function getKey<S extends StringOrSymbol>(key: S) {
|
||||
>getKey : Symbol(getKey, Decl(noImplicitSymbolToString.ts, 17, 38))
|
||||
>S : Symbol(S, Decl(noImplicitSymbolToString.ts, 19, 16))
|
||||
>StringOrSymbol : Symbol(StringOrSymbol, Decl(noImplicitSymbolToString.ts, 12, 109))
|
||||
>key : Symbol(key, Decl(noImplicitSymbolToString.ts, 19, 42))
|
||||
>S : Symbol(S, Decl(noImplicitSymbolToString.ts, 19, 16))
|
||||
|
||||
return `${key} is the key`;
|
||||
>key : Symbol(key, Decl(noImplicitSymbolToString.ts, 19, 42))
|
||||
}
|
||||
|
||||
function getKey1<S extends symbol>(key: S) {
|
||||
>getKey1 : Symbol(getKey1, Decl(noImplicitSymbolToString.ts, 21, 1))
|
||||
>S : Symbol(S, Decl(noImplicitSymbolToString.ts, 23, 17))
|
||||
>key : Symbol(key, Decl(noImplicitSymbolToString.ts, 23, 35))
|
||||
>S : Symbol(S, Decl(noImplicitSymbolToString.ts, 23, 17))
|
||||
|
||||
let s1!: S;
|
||||
>s1 : Symbol(s1, Decl(noImplicitSymbolToString.ts, 24, 7))
|
||||
>S : Symbol(S, Decl(noImplicitSymbolToString.ts, 23, 17))
|
||||
|
||||
`${s1}`;
|
||||
>s1 : Symbol(s1, Decl(noImplicitSymbolToString.ts, 24, 7))
|
||||
|
||||
s1 + '';
|
||||
>s1 : Symbol(s1, Decl(noImplicitSymbolToString.ts, 24, 7))
|
||||
|
||||
+s1;
|
||||
>s1 : Symbol(s1, Decl(noImplicitSymbolToString.ts, 24, 7))
|
||||
|
||||
let s2!: S | string;
|
||||
>s2 : Symbol(s2, Decl(noImplicitSymbolToString.ts, 29, 7))
|
||||
>S : Symbol(S, Decl(noImplicitSymbolToString.ts, 23, 17))
|
||||
|
||||
`${s2}`;
|
||||
>s2 : Symbol(s2, Decl(noImplicitSymbolToString.ts, 29, 7))
|
||||
|
||||
s2 + '';
|
||||
>s2 : Symbol(s2, Decl(noImplicitSymbolToString.ts, 29, 7))
|
||||
|
||||
+s2;
|
||||
>s2 : Symbol(s2, Decl(noImplicitSymbolToString.ts, 29, 7))
|
||||
}
|
||||
|
||||
function getKey2<S extends string>(key: S) {
|
||||
>getKey2 : Symbol(getKey2, Decl(noImplicitSymbolToString.ts, 33, 1))
|
||||
>S : Symbol(S, Decl(noImplicitSymbolToString.ts, 35, 17))
|
||||
>key : Symbol(key, Decl(noImplicitSymbolToString.ts, 35, 35))
|
||||
>S : Symbol(S, Decl(noImplicitSymbolToString.ts, 35, 17))
|
||||
|
||||
let s1!: S;
|
||||
>s1 : Symbol(s1, Decl(noImplicitSymbolToString.ts, 36, 7))
|
||||
>S : Symbol(S, Decl(noImplicitSymbolToString.ts, 35, 17))
|
||||
|
||||
`${s1}`;
|
||||
>s1 : Symbol(s1, Decl(noImplicitSymbolToString.ts, 36, 7))
|
||||
|
||||
s1 + '';
|
||||
>s1 : Symbol(s1, Decl(noImplicitSymbolToString.ts, 36, 7))
|
||||
|
||||
+s1;
|
||||
>s1 : Symbol(s1, Decl(noImplicitSymbolToString.ts, 36, 7))
|
||||
|
||||
let s2!: S | symbol;
|
||||
>s2 : Symbol(s2, Decl(noImplicitSymbolToString.ts, 41, 7))
|
||||
>S : Symbol(S, Decl(noImplicitSymbolToString.ts, 35, 17))
|
||||
|
||||
`${s2}`;
|
||||
>s2 : Symbol(s2, Decl(noImplicitSymbolToString.ts, 41, 7))
|
||||
|
||||
s2 + '';
|
||||
>s2 : Symbol(s2, Decl(noImplicitSymbolToString.ts, 41, 7))
|
||||
|
||||
+s2;
|
||||
>s2 : Symbol(s2, Decl(noImplicitSymbolToString.ts, 41, 7))
|
||||
}
|
||||
|
||||
|
||||
@@ -36,3 +36,92 @@ const templateStrUnion = `union with number ${symbolUnionNumber} and union with
|
||||
>symbolUnionNumber : number | symbol
|
||||
>symbolUnionString : string | symbol
|
||||
|
||||
|
||||
// Fix #44462
|
||||
|
||||
type StringOrSymbol = string | symbol;
|
||||
>StringOrSymbol : StringOrSymbol
|
||||
|
||||
function getKey<S extends StringOrSymbol>(key: S) {
|
||||
>getKey : <S extends StringOrSymbol>(key: S) => string
|
||||
>key : S
|
||||
|
||||
return `${key} is the key`;
|
||||
>`${key} is the key` : string
|
||||
>key : S
|
||||
}
|
||||
|
||||
function getKey1<S extends symbol>(key: S) {
|
||||
>getKey1 : <S extends symbol>(key: S) => void
|
||||
>key : S
|
||||
|
||||
let s1!: S;
|
||||
>s1 : S
|
||||
|
||||
`${s1}`;
|
||||
>`${s1}` : string
|
||||
>s1 : S
|
||||
|
||||
s1 + '';
|
||||
>s1 + '' : string
|
||||
>s1 : S
|
||||
>'' : ""
|
||||
|
||||
+s1;
|
||||
>+s1 : number
|
||||
>s1 : S
|
||||
|
||||
let s2!: S | string;
|
||||
>s2 : string | S
|
||||
|
||||
`${s2}`;
|
||||
>`${s2}` : string
|
||||
>s2 : string | S
|
||||
|
||||
s2 + '';
|
||||
>s2 + '' : string
|
||||
>s2 : string | S
|
||||
>'' : ""
|
||||
|
||||
+s2;
|
||||
>+s2 : number
|
||||
>s2 : string | S
|
||||
}
|
||||
|
||||
function getKey2<S extends string>(key: S) {
|
||||
>getKey2 : <S extends string>(key: S) => void
|
||||
>key : S
|
||||
|
||||
let s1!: S;
|
||||
>s1 : S
|
||||
|
||||
`${s1}`;
|
||||
>`${s1}` : string
|
||||
>s1 : S
|
||||
|
||||
s1 + '';
|
||||
>s1 + '' : string
|
||||
>s1 : S
|
||||
>'' : ""
|
||||
|
||||
+s1;
|
||||
>+s1 : number
|
||||
>s1 : S
|
||||
|
||||
let s2!: S | symbol;
|
||||
>s2 : symbol | S
|
||||
|
||||
`${s2}`;
|
||||
>`${s2}` : string
|
||||
>s2 : symbol | S
|
||||
|
||||
s2 + '';
|
||||
>s2 + '' : string
|
||||
>s2 : symbol | S
|
||||
>'' : ""
|
||||
|
||||
+s2;
|
||||
>+s2 : number
|
||||
>s2 : symbol | S
|
||||
}
|
||||
|
||||
|
||||
@@ -11,3 +11,36 @@ let symbolUnionNumber!: symbol | number;
|
||||
let symbolUnionString!: symbol | string;
|
||||
|
||||
const templateStrUnion = `union with number ${symbolUnionNumber} and union with string ${symbolUnionString}`;
|
||||
|
||||
|
||||
// Fix #44462
|
||||
|
||||
type StringOrSymbol = string | symbol;
|
||||
|
||||
function getKey<S extends StringOrSymbol>(key: S) {
|
||||
return `${key} is the key`;
|
||||
}
|
||||
|
||||
function getKey1<S extends symbol>(key: S) {
|
||||
let s1!: S;
|
||||
`${s1}`;
|
||||
s1 + '';
|
||||
+s1;
|
||||
|
||||
let s2!: S | string;
|
||||
`${s2}`;
|
||||
s2 + '';
|
||||
+s2;
|
||||
}
|
||||
|
||||
function getKey2<S extends string>(key: S) {
|
||||
let s1!: S;
|
||||
`${s1}`;
|
||||
s1 + '';
|
||||
+s1;
|
||||
|
||||
let s2!: S | symbol;
|
||||
`${s2}`;
|
||||
s2 + '';
|
||||
+s2;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user