diff --git a/crates/stc_ts_file_analyzer/src/analyzer/assign/mod.rs b/crates/stc_ts_file_analyzer/src/analyzer/assign/mod.rs index 81f4436dea..88e05ecec3 100644 --- a/crates/stc_ts_file_analyzer/src/analyzer/assign/mod.rs +++ b/crates/stc_ts_file_analyzer/src/analyzer/assign/mod.rs @@ -6,9 +6,9 @@ use stc_ts_errors::{ DebugExt, ErrorKind, }; use stc_ts_types::{ - Array, Conditional, EnumVariant, Index, Instance, Interface, Intersection, IntrinsicKind, Key, KeywordType, LitType, Mapped, - PropertySignature, QueryExpr, QueryType, Readonly, Ref, StringMapping, ThisType, Tuple, TupleElement, Type, TypeElement, TypeLit, - TypeParam, + Array, Conditional, EnumVariant, Index, IndexedAccessType, Instance, Interface, Intersection, IntrinsicKind, Key, KeywordType, LitType, + Mapped, PropertySignature, QueryExpr, QueryType, Readonly, Ref, StringMapping, ThisType, Tuple, TupleElement, Type, TypeElement, + TypeLit, TypeParam, }; use stc_utils::{cache::Freeze, dev_span, ext::SpanExt, stack}; use swc_atoms::js_word; @@ -521,12 +521,72 @@ impl Analyzer<'_, '_> { } } - match ty { + match ty.normalize() { Type::EnumVariant(e @ EnumVariant { name: Some(..), .. }) => { if opts.ignore_enum_variant_name { return Ok(Cow::Owned(Type::EnumVariant(EnumVariant { name: None, ..e.clone() }))); } } + Type::IndexedAccessType(IndexedAccessType { + obj_type: + obj @ box Type::Param(TypeParam { + span: p_span, + name, + constraint, + .. + }), + index_type: + box Type::Index(Index { + ty: + box Type::Param(TypeParam { + constraint: None, + default: None, + name: rhs_param_name, + .. + }), + .. + }), + .. + }) if name.eq(rhs_param_name) => { + let create_index_accessed_type = |ty: Box, obj| { + Type::IndexedAccessType(IndexedAccessType { + span, + readonly: false, + obj_type: obj, + index_type: ty, + metadata: Default::default(), + tracker: Default::default(), + }) + }; + + let gen_keyword_type = |kind| { + Type::Keyword(KeywordType { + span, + kind, + metadata: Default::default(), + tracker: Default::default(), + }) + }; + + return Ok(Cow::Owned(Type::new_union( + span, + [ + create_index_accessed_type( + Box::new(gen_keyword_type(TsKeywordTypeKind::TsStringKeyword)), + Box::new(*obj.clone()), + ), + create_index_accessed_type( + Box::new(gen_keyword_type(TsKeywordTypeKind::TsNumberKeyword)), + Box::new(*obj.clone()), + ), + create_index_accessed_type( + Box::new(gen_keyword_type(TsKeywordTypeKind::TsSymbolKeyword)), + Box::new(*obj.clone()), + ), + ], + ))); + } + Type::Conditional(..) | Type::IndexedAccessType(..) | Type::Alias(..) @@ -1965,10 +2025,23 @@ impl Analyzer<'_, '_> { if results.iter().any(Result::is_ok) { return Ok(()); } + + if let Type::Param(TypeParam { + constraint: Some(box c), .. + }) = rhs + { + if let Ok(result) = self.normalize(Some(span), Cow::Borrowed(c), Default::default()) { + return self + .assign_with_opts(data, to, result.normalize(), opts) + .context("tried to assign a type_param at union"); + } + } + let normalized = lu.types.iter().any(|ty| match ty.normalize() { Type::TypeLit(ty) => ty.metadata.normalized, _ => false, }); + let errors = results.into_iter().map(Result::unwrap_err).collect(); let should_use_single_error = normalized || lu.types.iter().all(|ty| { @@ -1984,6 +2057,7 @@ impl Analyzer<'_, '_> { || ty.is_type_param() || ty.is_class() || ty.is_class_def() + || ty.is_indexed_access_type() }); if should_use_single_error { diff --git a/crates/stc_ts_type_checker/tests/conformance.pass.txt b/crates/stc_ts_type_checker/tests/conformance.pass.txt index 7620551fec..2e71241343 100644 --- a/crates/stc_ts_type_checker/tests/conformance.pass.txt +++ b/crates/stc_ts_type_checker/tests/conformance.pass.txt @@ -1807,6 +1807,7 @@ jsdoc/parseLinkTag.ts jsdoc/parseThrowsTag.ts jsdoc/seeTag1.ts jsdoc/seeTag2.ts +jsdoc/typeParameterExtendsUnionConstraintDistributed.ts jsx/tsxEmitSpreadAttribute.ts moduleResolution/importFromDot.ts moduleResolution/packageJsonImportsExportsOptionCompat.ts diff --git a/crates/stc_ts_type_checker/tests/conformance/jsdoc/typeParameterExtendsUnionConstraintDistributed.error-diff.json b/crates/stc_ts_type_checker/tests/conformance/jsdoc/typeParameterExtendsUnionConstraintDistributed.error-diff.json deleted file mode 100644 index 9514d9dda2..0000000000 --- a/crates/stc_ts_type_checker/tests/conformance/jsdoc/typeParameterExtendsUnionConstraintDistributed.error-diff.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "required_errors": {}, - "required_error_lines": {}, - "extra_errors": { - "TS2322": 1 - }, - "extra_error_lines": { - "TS2322": [ - 2 - ] - } -} \ No newline at end of file diff --git a/crates/stc_ts_type_checker/tests/conformance/jsdoc/typeParameterExtendsUnionConstraintDistributed.stats.rust-debug b/crates/stc_ts_type_checker/tests/conformance/jsdoc/typeParameterExtendsUnionConstraintDistributed.stats.rust-debug index 0498397634..c086b5ab15 100644 --- a/crates/stc_ts_type_checker/tests/conformance/jsdoc/typeParameterExtendsUnionConstraintDistributed.stats.rust-debug +++ b/crates/stc_ts_type_checker/tests/conformance/jsdoc/typeParameterExtendsUnionConstraintDistributed.stats.rust-debug @@ -1,6 +1,6 @@ Stats { required_error: 0, matched_error: 0, - extra_error: 1, + extra_error: 0, panic: 0, } \ No newline at end of file diff --git a/crates/stc_ts_type_checker/tests/tsc-stats.rust-debug b/crates/stc_ts_type_checker/tests/tsc-stats.rust-debug index 02553a0cb6..b11d9b974e 100644 --- a/crates/stc_ts_type_checker/tests/tsc-stats.rust-debug +++ b/crates/stc_ts_type_checker/tests/tsc-stats.rust-debug @@ -1,6 +1,6 @@ Stats { required_error: 3502, matched_error: 6533, - extra_error: 764, + extra_error: 763, panic: 73, } \ No newline at end of file