Merge pull request #12033 from Microsoft/add-undefined-to-default-valued-parameters

Add undefined to default-initialised parameters
This commit is contained in:
Nathan Shively-Sanders 2017-02-13 13:30:46 -08:00 committed by GitHub
commit 46d9f37020
9 changed files with 534 additions and 11 deletions

View file

@ -2690,7 +2690,11 @@ namespace ts {
writePunctuation(writer, SyntaxKind.ColonToken);
writeSpace(writer);
buildTypeDisplay(getTypeOfSymbol(p), writer, enclosingDeclaration, flags, symbolStack);
let type = getTypeOfSymbol(p);
if (isRequiredInitializedParameter(parameterNode)) {
type = includeFalsyTypes(type, TypeFlags.Undefined);
}
buildTypeDisplay(type, writer, enclosingDeclaration, flags, symbolStack);
}
function buildBindingPatternDisplay(bindingPattern: BindingPattern, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, symbolStack?: Symbol[]) {
@ -3271,6 +3275,16 @@ namespace ts {
return strictNullChecks && optional ? includeFalsyTypes(type, TypeFlags.Undefined) : type;
}
/** remove undefined from the annotated type of a parameter when there is an initializer (that doesn't include undefined) */
function removeOptionalityFromAnnotation(annotatedType: Type, declaration: VariableLikeDeclaration): Type {
const annotationIncludesUndefined = strictNullChecks &&
declaration.kind === SyntaxKind.Parameter &&
declaration.initializer &&
getFalsyFlags(annotatedType) & TypeFlags.Undefined &&
!(getFalsyFlags(checkExpression(declaration.initializer)) & TypeFlags.Undefined);
return annotationIncludesUndefined ? getNonNullableType(annotatedType) : annotatedType;
}
// Return the inferred type for a variable, parameter, or property declaration
function getTypeForVariableLikeDeclaration(declaration: VariableLikeDeclaration, includeOptionality: boolean): Type {
if (declaration.flags & NodeFlags.JavaScriptFile) {
@ -3304,7 +3318,8 @@ namespace ts {
// Use type from type annotation if one is present
if (declaration.type) {
return addOptionality(getTypeFromTypeNode(declaration.type), /*optional*/ declaration.questionToken && includeOptionality);
const declaredType = removeOptionalityFromAnnotation(getTypeFromTypeNode(declaration.type), declaration);
return addOptionality(declaredType, /*optional*/ declaration.questionToken && includeOptionality);
}
if ((compilerOptions.noImplicitAny || declaration.flags & NodeFlags.JavaScriptFile) &&
@ -5198,6 +5213,12 @@ namespace ts {
Debug.assert(parameterIndex >= 0);
return parameterIndex >= signature.minArgumentCount;
}
const iife = getImmediatelyInvokedFunctionExpression(node.parent);
if (iife) {
return !node.type &&
!node.dotDotDotToken &&
indexOf((node.parent as SignatureDeclaration).parameters, node) >= iife.arguments.length;
}
return false;
}
@ -20702,6 +20723,13 @@ namespace ts {
return false;
}
function isRequiredInitializedParameter(parameter: ParameterDeclaration) {
return strictNullChecks &&
!isOptionalParameter(parameter) &&
parameter.initializer &&
!(getModifierFlags(parameter) & ModifierFlags.ParameterPropertyModifier);
}
function getNodeCheckFlags(node: Node): NodeCheckFlags {
node = getParseTreeNode(node);
return node ? getNodeLinks(node).flags : undefined;
@ -20793,10 +20821,12 @@ namespace ts {
function writeTypeOfDeclaration(declaration: AccessorDeclaration | VariableLikeDeclaration, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: SymbolWriter) {
// Get type of the symbol if this is the valid symbol otherwise get type at location
const symbol = getSymbolOfNode(declaration);
const type = symbol && !(symbol.flags & (SymbolFlags.TypeLiteral | SymbolFlags.Signature))
let type = symbol && !(symbol.flags & (SymbolFlags.TypeLiteral | SymbolFlags.Signature))
? getWidenedLiteralType(getTypeOfSymbol(symbol))
: unknownType;
if (flags & TypeFormatFlags.AddUndefined) {
type = includeFalsyTypes(type, TypeFlags.Undefined);
}
getSymbolDisplayBuilder().buildTypeDisplay(type, writer, enclosingDeclaration, flags);
}
@ -20895,6 +20925,7 @@ namespace ts {
isTopLevelValueImportEqualsWithEntityName,
isDeclarationVisible,
isImplementationOfOverload,
isRequiredInitializedParameter,
writeTypeOfDeclaration,
writeReturnTypeOfSignatureDeclaration,
writeTypeOfExpression,

View file

@ -324,13 +324,20 @@ namespace ts {
function writeTypeOfDeclaration(declaration: AccessorDeclaration | VariableLikeDeclaration, type: TypeNode, getSymbolAccessibilityDiagnostic: GetSymbolAccessibilityDiagnostic) {
writer.getSymbolAccessibilityDiagnostic = getSymbolAccessibilityDiagnostic;
write(": ");
if (type) {
// use the checker's type, not the declared type,
// for non-optional initialized parameters that aren't a parameter property
const shouldUseResolverType = declaration.kind === SyntaxKind.Parameter &&
resolver.isRequiredInitializedParameter(declaration as ParameterDeclaration);
if (type && !shouldUseResolverType) {
// Write the type
emitType(type);
}
else {
errorNameNode = declaration.name;
resolver.writeTypeOfDeclaration(declaration, enclosingDeclaration, TypeFormatFlags.UseTypeOfFunction | TypeFormatFlags.UseTypeAliasValue, writer);
const format = TypeFormatFlags.UseTypeOfFunction | TypeFormatFlags.UseTypeAliasValue |
(shouldUseResolverType ? TypeFormatFlags.AddUndefined : 0);
resolver.writeTypeOfDeclaration(declaration, enclosingDeclaration, format, writer);
errorNameNode = undefined;
}
}

View file

@ -2474,7 +2474,8 @@
InFirstTypeArgument = 0x00000100, // Writing first type argument of the instantiated type
InTypeAlias = 0x00000200, // Writing type in type alias declaration
UseTypeAliasValue = 0x00000400, // Serialize the type instead of using type-alias. This is needed when we emit declaration file.
SuppressAnyReturnType = 0x00000800, // If the return type is any-like, don't offer a return type.
SuppressAnyReturnType = 0x00000800, // If the return type is any-like, don't offer a return type.
AddUndefined = 0x00001000, // Add undefined to types of initialized, non-optional parameters
}
export const enum SymbolFormatFlags {
@ -2579,6 +2580,7 @@
isDeclarationVisible(node: Declaration): boolean;
collectLinkedAliases(node: Identifier): Node[];
isImplementationOfOverload(node: FunctionLikeDeclaration): boolean;
isRequiredInitializedParameter(node: ParameterDeclaration): boolean;
writeTypeOfDeclaration(declaration: AccessorDeclaration | VariableLikeDeclaration, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: SymbolWriter): void;
writeReturnTypeOfSignatureDeclaration(signatureDeclaration: SignatureDeclaration, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: SymbolWriter): void;
writeTypeOfExpression(expr: Expression, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: SymbolWriter): void;

View file

@ -253,8 +253,8 @@ let eleven = (o => o.a(11))({ a: function(n) { return n; } });
// missing arguments
(function(x, undefined) { return x; })(42);
>(function(x, undefined) { return x; })(42) : number
>(function(x, undefined) { return x; }) : (x: number, undefined: any) => number
>function(x, undefined) { return x; } : (x: number, undefined: any) => number
>(function(x, undefined) { return x; }) : (x: number, undefined?: any) => number
>function(x, undefined) { return x; } : (x: number, undefined?: any) => number
>x : number
>undefined : any
>x : number
@ -262,8 +262,8 @@ let eleven = (o => o.a(11))({ a: function(n) { return n; } });
((x, y, z) => 42)();
>((x, y, z) => 42)() : number
>((x, y, z) => 42) : (x: any, y: any, z: any) => number
>(x, y, z) => 42 : (x: any, y: any, z: any) => number
>((x, y, z) => 42) : (x?: any, y?: any, z?: any) => number
>(x, y, z) => 42 : (x?: any, y?: any, z?: any) => number
>x : any
>y : any
>z : any

View file

@ -0,0 +1,112 @@
//// [defaultParameterAddsUndefinedWithStrictNullChecks.ts]
function f(addUndefined1 = "J", addUndefined2?: number) {
return addUndefined1.length + (addUndefined2 || 0);
}
function g(addUndefined = "J", addDefined: number) {
return addUndefined.length + addDefined;
}
let total = f() + f('a', 1) + f('b') + f(undefined, 2);
total = g('c', 3) + g(undefined, 4);
function foo1(x: string = "string", b: number) {
x.length;
}
function foo2(x = "string", b: number) {
x.length; // ok, should be string
}
function foo3(x: string | undefined = "string", b: number) {
x.length; // ok, should be string
}
function foo4(x: string | undefined = undefined, b: number) {
x; // should be string | undefined
}
// .d.ts should have `string | undefined` for foo1, foo2, foo3 and foo4
foo1(undefined, 1);
foo2(undefined, 1);
foo3(undefined, 1);
foo4(undefined, 1);
function removeUndefinedButNotFalse(x = true) {
if (x === false) {
return x;
}
}
declare const cond: boolean;
function removeNothing(y = cond ? true : undefined) {
if (y !== undefined) {
if (y === false) {
return y;
}
}
return true;
}
//// [defaultParameterAddsUndefinedWithStrictNullChecks.js]
function f(addUndefined1, addUndefined2) {
if (addUndefined1 === void 0) { addUndefined1 = "J"; }
return addUndefined1.length + (addUndefined2 || 0);
}
function g(addUndefined, addDefined) {
if (addUndefined === void 0) { addUndefined = "J"; }
return addUndefined.length + addDefined;
}
var total = f() + f('a', 1) + f('b') + f(undefined, 2);
total = g('c', 3) + g(undefined, 4);
function foo1(x, b) {
if (x === void 0) { x = "string"; }
x.length;
}
function foo2(x, b) {
if (x === void 0) { x = "string"; }
x.length; // ok, should be string
}
function foo3(x, b) {
if (x === void 0) { x = "string"; }
x.length; // ok, should be string
}
function foo4(x, b) {
if (x === void 0) { x = undefined; }
x; // should be string | undefined
}
// .d.ts should have `string | undefined` for foo1, foo2, foo3 and foo4
foo1(undefined, 1);
foo2(undefined, 1);
foo3(undefined, 1);
foo4(undefined, 1);
function removeUndefinedButNotFalse(x) {
if (x === void 0) { x = true; }
if (x === false) {
return x;
}
}
function removeNothing(y) {
if (y === void 0) { y = cond ? true : undefined; }
if (y !== undefined) {
if (y === false) {
return y;
}
}
return true;
}
//// [defaultParameterAddsUndefinedWithStrictNullChecks.d.ts]
declare function f(addUndefined1?: string, addUndefined2?: number): number;
declare function g(addUndefined: string | undefined, addDefined: number): number;
declare let total: number;
declare function foo1(x: string | undefined, b: number): void;
declare function foo2(x: string | undefined, b: number): void;
declare function foo3(x: string | undefined, b: number): void;
declare function foo4(x: string | undefined, b: number): void;
declare function removeUndefinedButNotFalse(x?: boolean): false | undefined;
declare const cond: boolean;
declare function removeNothing(y?: boolean | undefined): boolean;

View file

@ -0,0 +1,135 @@
=== tests/cases/compiler/defaultParameterAddsUndefinedWithStrictNullChecks.ts ===
function f(addUndefined1 = "J", addUndefined2?: number) {
>f : Symbol(f, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 0, 0))
>addUndefined1 : Symbol(addUndefined1, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 0, 11))
>addUndefined2 : Symbol(addUndefined2, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 0, 31))
return addUndefined1.length + (addUndefined2 || 0);
>addUndefined1.length : Symbol(String.length, Decl(lib.d.ts, --, --))
>addUndefined1 : Symbol(addUndefined1, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 0, 11))
>length : Symbol(String.length, Decl(lib.d.ts, --, --))
>addUndefined2 : Symbol(addUndefined2, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 0, 31))
}
function g(addUndefined = "J", addDefined: number) {
>g : Symbol(g, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 2, 1))
>addUndefined : Symbol(addUndefined, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 3, 11))
>addDefined : Symbol(addDefined, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 3, 30))
return addUndefined.length + addDefined;
>addUndefined.length : Symbol(String.length, Decl(lib.d.ts, --, --))
>addUndefined : Symbol(addUndefined, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 3, 11))
>length : Symbol(String.length, Decl(lib.d.ts, --, --))
>addDefined : Symbol(addDefined, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 3, 30))
}
let total = f() + f('a', 1) + f('b') + f(undefined, 2);
>total : Symbol(total, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 6, 3))
>f : Symbol(f, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 0, 0))
>f : Symbol(f, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 0, 0))
>f : Symbol(f, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 0, 0))
>f : Symbol(f, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 0, 0))
>undefined : Symbol(undefined)
total = g('c', 3) + g(undefined, 4);
>total : Symbol(total, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 6, 3))
>g : Symbol(g, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 2, 1))
>g : Symbol(g, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 2, 1))
>undefined : Symbol(undefined)
function foo1(x: string = "string", b: number) {
>foo1 : Symbol(foo1, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 7, 36))
>x : Symbol(x, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 9, 14))
>b : Symbol(b, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 9, 35))
x.length;
>x.length : Symbol(String.length, Decl(lib.d.ts, --, --))
>x : Symbol(x, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 9, 14))
>length : Symbol(String.length, Decl(lib.d.ts, --, --))
}
function foo2(x = "string", b: number) {
>foo2 : Symbol(foo2, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 11, 1))
>x : Symbol(x, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 13, 14))
>b : Symbol(b, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 13, 27))
x.length; // ok, should be string
>x.length : Symbol(String.length, Decl(lib.d.ts, --, --))
>x : Symbol(x, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 13, 14))
>length : Symbol(String.length, Decl(lib.d.ts, --, --))
}
function foo3(x: string | undefined = "string", b: number) {
>foo3 : Symbol(foo3, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 15, 1))
>x : Symbol(x, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 17, 14))
>b : Symbol(b, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 17, 47))
x.length; // ok, should be string
>x.length : Symbol(String.length, Decl(lib.d.ts, --, --))
>x : Symbol(x, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 17, 14))
>length : Symbol(String.length, Decl(lib.d.ts, --, --))
}
function foo4(x: string | undefined = undefined, b: number) {
>foo4 : Symbol(foo4, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 19, 1))
>x : Symbol(x, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 21, 14))
>undefined : Symbol(undefined)
>b : Symbol(b, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 21, 48))
x; // should be string | undefined
>x : Symbol(x, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 21, 14))
}
// .d.ts should have `string | undefined` for foo1, foo2, foo3 and foo4
foo1(undefined, 1);
>foo1 : Symbol(foo1, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 7, 36))
>undefined : Symbol(undefined)
foo2(undefined, 1);
>foo2 : Symbol(foo2, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 11, 1))
>undefined : Symbol(undefined)
foo3(undefined, 1);
>foo3 : Symbol(foo3, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 15, 1))
>undefined : Symbol(undefined)
foo4(undefined, 1);
>foo4 : Symbol(foo4, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 19, 1))
>undefined : Symbol(undefined)
function removeUndefinedButNotFalse(x = true) {
>removeUndefinedButNotFalse : Symbol(removeUndefinedButNotFalse, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 31, 19))
>x : Symbol(x, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 34, 36))
if (x === false) {
>x : Symbol(x, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 34, 36))
return x;
>x : Symbol(x, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 34, 36))
}
}
declare const cond: boolean;
>cond : Symbol(cond, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 40, 13))
function removeNothing(y = cond ? true : undefined) {
>removeNothing : Symbol(removeNothing, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 40, 28))
>y : Symbol(y, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 41, 23))
>cond : Symbol(cond, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 40, 13))
>undefined : Symbol(undefined)
if (y !== undefined) {
>y : Symbol(y, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 41, 23))
>undefined : Symbol(undefined)
if (y === false) {
>y : Symbol(y, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 41, 23))
return y;
>y : Symbol(y, Decl(defaultParameterAddsUndefinedWithStrictNullChecks.ts, 41, 23))
}
}
return true;
}

View file

@ -0,0 +1,180 @@
=== tests/cases/compiler/defaultParameterAddsUndefinedWithStrictNullChecks.ts ===
function f(addUndefined1 = "J", addUndefined2?: number) {
>f : (addUndefined1?: string, addUndefined2?: number | undefined) => number
>addUndefined1 : string
>"J" : "J"
>addUndefined2 : number | undefined
return addUndefined1.length + (addUndefined2 || 0);
>addUndefined1.length + (addUndefined2 || 0) : number
>addUndefined1.length : number
>addUndefined1 : string
>length : number
>(addUndefined2 || 0) : number
>addUndefined2 || 0 : number
>addUndefined2 : number | undefined
>0 : 0
}
function g(addUndefined = "J", addDefined: number) {
>g : (addUndefined: string | undefined, addDefined: number) => number
>addUndefined : string
>"J" : "J"
>addDefined : number
return addUndefined.length + addDefined;
>addUndefined.length + addDefined : number
>addUndefined.length : number
>addUndefined : string
>length : number
>addDefined : number
}
let total = f() + f('a', 1) + f('b') + f(undefined, 2);
>total : number
>f() + f('a', 1) + f('b') + f(undefined, 2) : number
>f() + f('a', 1) + f('b') : number
>f() + f('a', 1) : number
>f() : number
>f : (addUndefined1?: string, addUndefined2?: number | undefined) => number
>f('a', 1) : number
>f : (addUndefined1?: string, addUndefined2?: number | undefined) => number
>'a' : "a"
>1 : 1
>f('b') : number
>f : (addUndefined1?: string, addUndefined2?: number | undefined) => number
>'b' : "b"
>f(undefined, 2) : number
>f : (addUndefined1?: string, addUndefined2?: number | undefined) => number
>undefined : undefined
>2 : 2
total = g('c', 3) + g(undefined, 4);
>total = g('c', 3) + g(undefined, 4) : number
>total : number
>g('c', 3) + g(undefined, 4) : number
>g('c', 3) : number
>g : (addUndefined: string | undefined, addDefined: number) => number
>'c' : "c"
>3 : 3
>g(undefined, 4) : number
>g : (addUndefined: string | undefined, addDefined: number) => number
>undefined : undefined
>4 : 4
function foo1(x: string = "string", b: number) {
>foo1 : (x: string | undefined, b: number) => void
>x : string
>"string" : "string"
>b : number
x.length;
>x.length : number
>x : string
>length : number
}
function foo2(x = "string", b: number) {
>foo2 : (x: string | undefined, b: number) => void
>x : string
>"string" : "string"
>b : number
x.length; // ok, should be string
>x.length : number
>x : string
>length : number
}
function foo3(x: string | undefined = "string", b: number) {
>foo3 : (x: string | undefined, b: number) => void
>x : string
>"string" : "string"
>b : number
x.length; // ok, should be string
>x.length : number
>x : string
>length : number
}
function foo4(x: string | undefined = undefined, b: number) {
>foo4 : (x: string | undefined, b: number) => void
>x : string | undefined
>undefined : undefined
>b : number
x; // should be string | undefined
>x : string | undefined
}
// .d.ts should have `string | undefined` for foo1, foo2, foo3 and foo4
foo1(undefined, 1);
>foo1(undefined, 1) : void
>foo1 : (x: string | undefined, b: number) => void
>undefined : undefined
>1 : 1
foo2(undefined, 1);
>foo2(undefined, 1) : void
>foo2 : (x: string | undefined, b: number) => void
>undefined : undefined
>1 : 1
foo3(undefined, 1);
>foo3(undefined, 1) : void
>foo3 : (x: string | undefined, b: number) => void
>undefined : undefined
>1 : 1
foo4(undefined, 1);
>foo4(undefined, 1) : void
>foo4 : (x: string | undefined, b: number) => void
>undefined : undefined
>1 : 1
function removeUndefinedButNotFalse(x = true) {
>removeUndefinedButNotFalse : (x?: boolean) => false | undefined
>x : boolean
>true : true
if (x === false) {
>x === false : boolean
>x : boolean
>false : false
return x;
>x : false
}
}
declare const cond: boolean;
>cond : boolean
function removeNothing(y = cond ? true : undefined) {
>removeNothing : (y?: boolean | undefined) => boolean
>y : boolean | undefined
>cond ? true : undefined : true | undefined
>cond : boolean
>true : true
>undefined : undefined
if (y !== undefined) {
>y !== undefined : boolean
>y : boolean | undefined
>undefined : undefined
if (y === false) {
>y === false : boolean
>y : boolean
>false : false
return y;
>y : false
}
}
return true;
>true : true
}

View file

@ -0,0 +1,51 @@
// @strictNullChecks: true
// @declaration: true
function f(addUndefined1 = "J", addUndefined2?: number) {
return addUndefined1.length + (addUndefined2 || 0);
}
function g(addUndefined = "J", addDefined: number) {
return addUndefined.length + addDefined;
}
let total = f() + f('a', 1) + f('b') + f(undefined, 2);
total = g('c', 3) + g(undefined, 4);
function foo1(x: string = "string", b: number) {
x.length;
}
function foo2(x = "string", b: number) {
x.length; // ok, should be string
}
function foo3(x: string | undefined = "string", b: number) {
x.length; // ok, should be string
}
function foo4(x: string | undefined = undefined, b: number) {
x; // should be string | undefined
}
// .d.ts should have `string | undefined` for foo1, foo2, foo3 and foo4
foo1(undefined, 1);
foo2(undefined, 1);
foo3(undefined, 1);
foo4(undefined, 1);
function removeUndefinedButNotFalse(x = true) {
if (x === false) {
return x;
}
}
declare const cond: boolean;
function removeNothing(y = cond ? true : undefined) {
if (y !== undefined) {
if (y === false) {
return y;
}
}
return true;
}

View file

@ -0,0 +1,5 @@
/// <reference path='fourslash.ts'/>
// @strictNullChecks: true
////var iife = (function foo/*1*/(x, y) { return x })(12);
verify.quickInfoAt('1', '(local function) foo(x: number, y?: undefined): number');