From 5059ece95a2bf941779213e34dd18997d16a7140 Mon Sep 17 00:00:00 2001 From: CPunisher <1343316114@qq.com> Date: Sat, 15 Feb 2025 08:33:37 +0800 Subject: [PATCH] fix(typescript): Improve type inferring for undefined and null (#10038) I remember doing that by design, but I forget why. Now let's align it with tsc --- .changeset/nasty-days-help.md | 6 ++++++ crates/swc_typescript/src/fast_dts/inferrer.rs | 6 +++++- crates/swc_typescript/src/fast_dts/types.rs | 6 +++--- crates/swc_typescript/tests/deno_test.rs | 8 ++++---- crates/swc_typescript/tests/oxc_fixture/as-const.snap | 6 +++--- 5 files changed, 21 insertions(+), 11 deletions(-) create mode 100644 .changeset/nasty-days-help.md diff --git a/.changeset/nasty-days-help.md b/.changeset/nasty-days-help.md new file mode 100644 index 000000000000..5c22ecec915b --- /dev/null +++ b/.changeset/nasty-days-help.md @@ -0,0 +1,6 @@ +--- +swc_core: patch +swc_typescript: patch +--- + +fix(typescript): Improve type inferring for undefined and null diff --git a/crates/swc_typescript/src/fast_dts/inferrer.rs b/crates/swc_typescript/src/fast_dts/inferrer.rs index 5e25c6ce9508..3159ccdfda04 100644 --- a/crates/swc_typescript/src/fast_dts/inferrer.rs +++ b/crates/swc_typescript/src/fast_dts/inferrer.rs @@ -14,12 +14,16 @@ use super::{ impl FastDts { pub(crate) fn infer_type_from_expr(&mut self, e: &Expr) -> Option> { match e { + Expr::Ident(ident) if ident.sym.as_str() == "undefined" => { + Some(ts_keyword_type(TsKeywordTypeKind::TsUndefinedKeyword)) + } Expr::Lit(lit) => match lit { Lit::Str(_) => Some(ts_keyword_type(TsKeywordTypeKind::TsStringKeyword)), Lit::Bool(_) => Some(ts_keyword_type(TsKeywordTypeKind::TsBooleanKeyword)), Lit::Num(_) => Some(ts_keyword_type(TsKeywordTypeKind::TsNumberKeyword)), Lit::BigInt(_) => Some(ts_keyword_type(TsKeywordTypeKind::TsBigIntKeyword)), - Lit::Null(_) | Lit::Regex(_) | Lit::JSXText(_) => None, + Lit::Null(_) => Some(ts_keyword_type(TsKeywordTypeKind::TsNullKeyword)), + Lit::Regex(_) | Lit::JSXText(_) => None, }, Expr::Tpl(_) => Some(ts_keyword_type(TsKeywordTypeKind::TsStringKeyword)), Expr::Fn(fn_expr) => self.transform_fn_to_ts_type( diff --git a/crates/swc_typescript/src/fast_dts/types.rs b/crates/swc_typescript/src/fast_dts/types.rs index 5a5e95074307..efe35ef27f57 100644 --- a/crates/swc_typescript/src/fast_dts/types.rs +++ b/crates/swc_typescript/src/fast_dts/types.rs @@ -20,12 +20,12 @@ impl FastDts { pub(crate) fn transform_expr_to_ts_type(&mut self, expr: &Expr) -> Option> { match expr { Expr::Ident(ident) if ident.sym == "undefined" => { - Some(ts_keyword_type(TsKeywordTypeKind::TsAnyKeyword)) + Some(ts_keyword_type(TsKeywordTypeKind::TsUndefinedKeyword)) } Expr::Lit(lit) => match lit { Lit::Str(string) => Some(ts_lit_type(TsLit::Str(string.clone()))), Lit::Bool(b) => Some(ts_lit_type(TsLit::Bool(*b))), - Lit::Null(_) => Some(ts_keyword_type(TsKeywordTypeKind::TsAnyKeyword)), + Lit::Null(_) => Some(ts_keyword_type(TsKeywordTypeKind::TsNullKeyword)), Lit::Num(number) => Some(ts_lit_type(TsLit::Number(number.clone()))), Lit::BigInt(big_int) => Some(ts_lit_type(TsLit::BigInt(big_int.clone()))), Lit::Regex(_) | Lit::JSXText(_) => None, @@ -274,7 +274,7 @@ impl FastDts { elements.push(TsTupleElement { span: DUMMY_SP, label: None, - ty: ts_keyword_type(TsKeywordTypeKind::TsAnyKeyword), + ty: ts_keyword_type(TsKeywordTypeKind::TsUndefinedKeyword), }); continue; }; diff --git a/crates/swc_typescript/tests/deno_test.rs b/crates/swc_typescript/tests/deno_test.rs index df3702414244..5c41b3d2e04c 100644 --- a/crates/swc_typescript/tests/deno_test.rs +++ b/crates/swc_typescript/tests/deno_test.rs @@ -267,7 +267,7 @@ fn dts_as_const() { ); transform_dts_test( r#"export const foo = [1, ,2] as const;"#, - "export declare const foo: readonly [1, any, 2];", + "export declare const foo: readonly [1, undefined, 2];", ); transform_dts_test( @@ -277,7 +277,7 @@ fn dts_as_const() { readonly bool: true; readonly bool2: false; readonly num: 42; - readonly nullish: any; + readonly nullish: null; };"#, ); @@ -331,11 +331,11 @@ fn dts_literal_inference() { ); transform_dts_test( r#"export const foo = null;"#, - "export declare const foo: any;", + "export declare const foo: null;", ); transform_dts_test( r#"export let foo = undefined;"#, - "export declare let foo: any;", + "export declare let foo: undefined;", ); transform_dts_test( r#"export let foo = 10n;"#, diff --git a/crates/swc_typescript/tests/oxc_fixture/as-const.snap b/crates/swc_typescript/tests/oxc_fixture/as-const.snap index 6234566d8094..296aeff7f209 100644 --- a/crates/swc_typescript/tests/oxc_fixture/as-const.snap +++ b/crates/swc_typescript/tests/oxc_fixture/as-const.snap @@ -6,15 +6,15 @@ declare const F: { readonly number: 1.23; readonly bigint: -123n; readonly boolean: true; - readonly null: any; - readonly undefined: any; + readonly null: null; + readonly undefined: undefined; readonly function: (a: string) => void; readonly arrow: (a: string) => void; readonly object: { readonly a: "a"; readonly b: "b"; }; - readonly array: readonly ["a", any, { + readonly array: readonly ["a", undefined, { readonly b: "\n"; }]; };