diff --git a/crates/stc_ts_file_analyzer/src/analyzer/assign/function.rs b/crates/stc_ts_file_analyzer/src/analyzer/assign/function.rs
index fe0285e131..cb356b3b28 100644
--- a/crates/stc_ts_file_analyzer/src/analyzer/assign/function.rs
+++ b/crates/stc_ts_file_analyzer/src/analyzer/assign/function.rs
@@ -1,4 +1,4 @@
-use std::{borrow::Cow, cmp::max};
+use std::{borrow::Cow, cmp::max, iter::Peekable};
use fxhash::FxHashMap;
use itertools::Itertools;
@@ -7,10 +7,10 @@ use stc_ts_errors::{
debug::{dump_type_map, force_dump_type_as_string},
DebugExt, ErrorKind,
};
-use stc_ts_types::{Constructor, FnParam, Function, IdCtx, Key, KeywordType, LitType, Type, TypeElement, TypeParamDecl};
+use stc_ts_types::{Constructor, FnParam, Function, IdCtx, Key, KeywordType, LitType, SpreadLike, Type, TypeElement, TypeParamDecl};
use stc_utils::{cache::Freeze, dev_span, stack};
use swc_atoms::js_word;
-use swc_common::{Spanned, SyntaxContext, TypeEq};
+use swc_common::{Span, Spanned, SyntaxContext, TypeEq};
use swc_ecma_ast::TsKeywordTypeKind;
use tracing::debug;
@@ -816,6 +816,125 @@ impl Analyzer<'_, '_> {
Ok(())
}
+ fn relate_spread_likes<'a, 'l, 'r, T, LI, RI>(
+ &'a mut self,
+ span: Span,
+ li: &mut Peekable
,
+ ri: &mut Peekable,
+ relate: &mut impl FnMut(&mut Self, &Type, &Type) -> VResult<()>,
+ ) -> VResult<()>
+ where
+ T: SpreadLike,
+ LI: Iterator- + Clone,
+ RI: Iterator
- + Clone,
+ {
+ let _tracing = dev_span!("relate_spread_likes");
+ let li_count = li.clone().count();
+ let ri_count = ri.clone().count();
+
+ while let (Some(..), Some(..)) = (li.peek(), ri.peek()) {
+ let l = li.peek().copied().cloned().unwrap();
+ let r = ri.peek().copied().cloned().unwrap();
+
+ match (l.is_spread(), r.is_spread()) {
+ (true, true) => {
+ li.next();
+ ri.next();
+
+ relate(self, &l.ty(), &r.ty()).context("failed to relate a spread item to another one")?;
+ }
+ (true, false) => {
+ li.next();
+
+ for (idx, r) in ri.into_iter().enumerate() {
+ let le = self
+ .access_property(
+ span,
+ &l.ty(),
+ &Key::Num(RNumber {
+ span: l.span(),
+ value: idx as f64,
+ raw: None,
+ }),
+ TypeOfMode::RValue,
+ IdCtx::Var,
+ AccessPropertyOpts {
+ disallow_indexing_array_with_string: true,
+ disallow_creating_indexed_type_from_ty_els: true,
+ disallow_indexing_class_with_computed: true,
+ disallow_inexact: true,
+ use_last_element_for_tuple_on_out_of_bound: true,
+ disallow_creating_indexed_type_for_type_params: true,
+ ..Default::default()
+ },
+ )
+ .unwrap_or_else(|_| l.ty().clone());
+
+ relate(self, &le, r.ty()).with_context(|| {
+ format!(
+ "l: spread + {} (from {}); r: non-spread + {}; idx = {}",
+ force_dump_type_as_string(&le),
+ force_dump_type_as_string(&l.ty()),
+ force_dump_type_as_string(r.ty()),
+ idx
+ )
+ })?;
+ }
+
+ return Ok(());
+ }
+ (false, true) => {
+ ri.next();
+
+ for (idx, l) in li.into_iter().enumerate() {
+ let re = self
+ .access_property(
+ span,
+ &r.ty(),
+ &Key::Num(RNumber {
+ span: r.span(),
+ value: idx as f64,
+ raw: None,
+ }),
+ TypeOfMode::RValue,
+ IdCtx::Var,
+ AccessPropertyOpts {
+ disallow_indexing_array_with_string: true,
+ disallow_creating_indexed_type_from_ty_els: true,
+ disallow_indexing_class_with_computed: true,
+ disallow_inexact: true,
+ use_last_element_for_tuple_on_out_of_bound: true,
+ disallow_creating_indexed_type_for_type_params: true,
+ ..Default::default()
+ },
+ )
+ .unwrap_or_else(|_| r.ty().clone());
+
+ relate(self, l.ty(), &re).with_context(|| {
+ format!(
+ "l: non-spread + {}; r: spread + {} (from {}); idx = {}",
+ force_dump_type_as_string(&l.ty()),
+ force_dump_type_as_string(&re),
+ force_dump_type_as_string(&r.ty()),
+ idx
+ )
+ })?;
+ }
+
+ return Ok(());
+ }
+ (false, false) => {
+ li.next();
+ ri.next();
+
+ relate(self, &l.ty(), &r.ty()).context("failed to relate a non-spread item")?;
+ }
+ }
+ }
+
+ Ok(())
+ }
+
/// # Validation of parameter count
///
/// A parameter named `this` is excluded.
@@ -837,24 +956,33 @@ impl Analyzer<'_, '_> {
let span = opts.span;
- let mut li = l.iter().filter(|p| {
- !matches!(
- p.pat,
- RPat::Ident(RBindingIdent {
- id: RIdent { sym: js_word!("this"), .. },
- ..
- })
- )
- });
- let mut ri = r.iter().filter(|p| {
- !matches!(
- p.pat,
- RPat::Ident(RBindingIdent {
- id: RIdent { sym: js_word!("this"), .. },
- ..
- })
- )
- });
+ let mut li = l
+ .iter()
+ .filter(|p| {
+ !matches!(
+ p.pat,
+ RPat::Ident(RBindingIdent {
+ id: RIdent { sym: js_word!("this"), .. },
+ ..
+ })
+ )
+ })
+ .peekable();
+ let mut ri = r
+ .iter()
+ .filter(|p| {
+ !matches!(
+ p.pat,
+ RPat::Ident(RBindingIdent {
+ id: RIdent { sym: js_word!("this"), .. },
+ ..
+ })
+ )
+ })
+ .peekable();
+
+ let li_count = li.clone().count();
+ let ri_count = ri.clone().count();
let l_has_rest = l.iter().any(|p| matches!(p.pat, RPat::Rest(..)));
@@ -899,124 +1027,19 @@ impl Analyzer<'_, '_> {
}
}
- loop {
- let l = li.next();
- let r = ri.next();
-
- let (Some(l), Some(r)) = (l, r) else {
- break
- };
-
- // TODO(kdy1): What should we do?
- if opts.allow_assignment_to_param {
- if let Ok(()) = self.assign_param(
- data,
- r,
- l,
- AssignOpts {
- allow_unknown_type: true,
- allow_assignment_to_param: false,
- ..opts
- },
- ) {
- continue;
- }
- }
-
- // A rest pattern is always the last
- match (&l.pat, &r.pat) {
- (RPat::Rest(..), RPat::Rest(..)) => {
- self.assign_param(data, l, r, opts)
- .with_context(|| "tried to assign a rest parameter to another rest parameter".to_string())?;
- break;
- }
-
- (RPat::Rest(..), _) => {
- // TODO(kdy1): Implement correct logic
-
- return Ok(());
- }
-
- (_, RPat::Rest(..)) => {
- // If r is an iterator, we should assign each element to l.
- if let Ok(r_iter) = self.get_iterator(span, Cow::Borrowed(&r.ty), Default::default()) {
- if let Ok(l_iter) = self.get_iterator(span, Cow::Borrowed(&l.ty), Default::default()) {
- for idx in 0..max(li.clone().count(), ri.clone().count()) {
- let le = self.access_property(
- span,
- &l_iter,
- &Key::Num(RNumber {
- span: l.span,
- value: idx as f64,
- raw: None,
- }),
- TypeOfMode::RValue,
- IdCtx::Var,
- AccessPropertyOpts {
- disallow_indexing_array_with_string: true,
- disallow_creating_indexed_type_from_ty_els: true,
- disallow_indexing_class_with_computed: true,
- disallow_inexact: true,
- ..Default::default()
- },
- )?;
-
- let re = self.access_property(
- span,
- &r_iter,
- &Key::Num(RNumber {
- span: r.span,
- value: idx as f64,
- raw: None,
- }),
- TypeOfMode::RValue,
- IdCtx::Var,
- AccessPropertyOpts {
- disallow_indexing_array_with_string: true,
- disallow_creating_indexed_type_from_ty_els: true,
- disallow_indexing_class_with_computed: true,
- disallow_inexact: true,
- use_last_element_for_tuple_on_out_of_bound: true,
- ..Default::default()
- },
- )?;
-
- self.assign_param_type(data, &le, &re, opts).with_context(|| {
- format!(
- "tried to assign a rest parameter to parameters; r_ty = {}",
- force_dump_type_as_string(&r.ty)
- )
- })?;
- }
- }
-
- return Ok(());
- }
-
- self.assign_param(data, l, r, opts)
- .context("tried to assign a rest parameter to parameters where r-ty is not a tuple")?;
-
- for l in li {
- self.assign_param(data, l, r, opts)
- .context("tried to assign a rest parameter to parameters where r-ty is not a tuple (iter)")?;
- }
-
- return Ok(());
- }
-
- _ => {
- self.assign_param(
- data,
- l,
- r,
- AssignOpts {
- allow_unknown_type: true,
- ..opts
- },
- )?;
- }
- }
- }
+ self.relate_spread_likes(span, &mut li, &mut ri, &mut |this, l, r| {
+ //
+ this.assign_param_type(
+ data,
+ l,
+ r,
+ AssignOpts {
+ allow_assignment_to_void: true,
+ ..opts
+ },
+ )
+ })
+ .context("failed to relate parameters")?;
Ok(())
}
diff --git a/crates/stc_ts_file_analyzer/src/analyzer/assign/type_el.rs b/crates/stc_ts_file_analyzer/src/analyzer/assign/type_el.rs
index f9c29af448..bccc823dd1 100644
--- a/crates/stc_ts_file_analyzer/src/analyzer/assign/type_el.rs
+++ b/crates/stc_ts_file_analyzer/src/analyzer/assign/type_el.rs
@@ -256,7 +256,12 @@ impl Analyzer<'_, '_> {
..opts
},
)
- .context("tried to assign to type elements by converting rhs to a type literal");
+ .with_context(|| {
+ format!(
+ "tried to assign to type elements by converting rhs to a type literal: {}",
+ force_dump_type_as_string(&rty)
+ )
+ });
}
return Err(ErrorKind::SimpleAssignFailed { span, cause: None }.into());
diff --git a/crates/stc_ts_file_analyzer/src/analyzer/expr/mod.rs b/crates/stc_ts_file_analyzer/src/analyzer/expr/mod.rs
index e61b3fbce4..045d50bdfc 100644
--- a/crates/stc_ts_file_analyzer/src/analyzer/expr/mod.rs
+++ b/crates/stc_ts_file_analyzer/src/analyzer/expr/mod.rs
@@ -656,6 +656,7 @@ pub(crate) struct AccessPropertyOpts {
/// obj11.foo; // Error TS2339
/// ```
pub disallow_creating_indexed_type_from_ty_els: bool,
+ pub disallow_creating_indexed_type_for_type_params: bool,
pub disallow_indexing_class_with_computed: bool,
@@ -2187,6 +2188,15 @@ impl Analyzer<'_, '_> {
}
}
+ if opts.disallow_creating_indexed_type_for_type_params {
+ return Err(ErrorKind::NoSuchProperty {
+ span,
+ obj: Some(Box::new(obj.clone())),
+ prop: Some(Box::new(prop.clone())),
+ }
+ .context("disallow_creating_indexed_type_for_type_params = true"));
+ }
+
let mut prop_ty = match prop {
Key::Computed(key) => key.ty.clone(),
Key::Normal { span, sym } => Box::new(Type::Lit(LitType {
@@ -2756,6 +2766,9 @@ impl Analyzer<'_, '_> {
}));
}
if opts.use_last_element_for_tuple_on_out_of_bound {
+ if elems.is_empty() {
+ return Ok(Type::any(span, Default::default()));
+ }
return Ok(*elems.last().unwrap().ty.clone());
}
@@ -2777,7 +2790,7 @@ impl Analyzer<'_, '_> {
}
return Err(ErrorKind::TupleIndexError {
- span: n.span(),
+ span,
index: v,
len: elems.len() as u64,
}
diff --git a/crates/stc_ts_file_analyzer/tests/tsc/conformance/types/typeRelationships/subtypesAndSuperTypes/subtypingWithCallSignaturesWithRestParameters/1.ts b/crates/stc_ts_file_analyzer/tests/tsc/conformance/types/typeRelationships/subtypesAndSuperTypes/subtypingWithCallSignaturesWithRestParameters/1.ts
new file mode 100644
index 0000000000..f22b8ced73
--- /dev/null
+++ b/crates/stc_ts_file_analyzer/tests/tsc/conformance/types/typeRelationships/subtypesAndSuperTypes/subtypingWithCallSignaturesWithRestParameters/1.ts
@@ -0,0 +1,12 @@
+// call signatures in derived types must have the same or fewer optional parameters as the base type
+
+interface Base {
+ a: (...args: number[]) => number;
+ a2: (x: number, ...z: number[]) => number;
+ a3: (x: number, y?: string, ...z: number[]) => number;
+ a4: (x?: number, y?: string, ...z: number[]) => number;
+}
+
+export interface I3B extends Base {
+ a: (x?: string) => number; // error, incompatible type
+}
diff --git a/crates/stc_ts_file_analyzer/tests/tsc/conformance/types/typeRelationships/subtypesAndSuperTypes/subtypingWithCallSignaturesWithRestParameters/1.tsc-errors.json b/crates/stc_ts_file_analyzer/tests/tsc/conformance/types/typeRelationships/subtypesAndSuperTypes/subtypingWithCallSignaturesWithRestParameters/1.tsc-errors.json
new file mode 100644
index 0000000000..c45e3b41e4
--- /dev/null
+++ b/crates/stc_ts_file_analyzer/tests/tsc/conformance/types/typeRelationships/subtypesAndSuperTypes/subtypingWithCallSignaturesWithRestParameters/1.tsc-errors.json
@@ -0,0 +1,8 @@
+[
+ {
+ "file": "tests/tsc/conformance/types/typeRelationships/subtypesAndSuperTypes/subtypingWithCallSignaturesWithRestParameters/1.ts",
+ "line": 10,
+ "col": 18,
+ "code": 2430
+ }
+]
\ No newline at end of file
diff --git a/crates/stc_ts_file_analyzer/tests/tsc/conformance/types/typeRelationships/subtypesAndSuperTypes/subtypingWithCallSignaturesWithRestParameters/2.ts b/crates/stc_ts_file_analyzer/tests/tsc/conformance/types/typeRelationships/subtypesAndSuperTypes/subtypingWithCallSignaturesWithRestParameters/2.ts
new file mode 100644
index 0000000000..071ac01f45
--- /dev/null
+++ b/crates/stc_ts_file_analyzer/tests/tsc/conformance/types/typeRelationships/subtypesAndSuperTypes/subtypingWithCallSignaturesWithRestParameters/2.ts
@@ -0,0 +1,46 @@
+// call signatures in derived types must have the same or fewer optional parameters as the base type
+
+interface Base {
+ a: (...args: number[]) => number;
+ a2: (x: number, ...z: number[]) => number;
+ a3: (x: number, y?: string, ...z: number[]) => number;
+ a4: (x?: number, y?: string, ...z: number[]) => number;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+export interface I10C extends Base {
+ a3: (x: number, ...z: number[]) => number; // error
+}
+
+
+
+
+
+
+
+
+
+
diff --git a/crates/stc_ts_file_analyzer/tests/tsc/conformance/types/typeRelationships/subtypesAndSuperTypes/subtypingWithCallSignaturesWithRestParameters/2.tsc-errors.json b/crates/stc_ts_file_analyzer/tests/tsc/conformance/types/typeRelationships/subtypesAndSuperTypes/subtypingWithCallSignaturesWithRestParameters/2.tsc-errors.json
new file mode 100644
index 0000000000..82d78c58c8
--- /dev/null
+++ b/crates/stc_ts_file_analyzer/tests/tsc/conformance/types/typeRelationships/subtypesAndSuperTypes/subtypingWithCallSignaturesWithRestParameters/2.tsc-errors.json
@@ -0,0 +1,8 @@
+[
+ {
+ "file": "tests/tsc/conformance/types/typeRelationships/subtypesAndSuperTypes/subtypingWithCallSignaturesWithRestParameters/2.ts",
+ "line": 34,
+ "col": 18,
+ "code": 2430
+ }
+]
\ No newline at end of file
diff --git a/crates/stc_ts_file_analyzer/tests/tsc/conformance/types/typeRelationships/subtypesAndSuperTypes/subtypingWithCallSignaturesWithRestParameters/3.ts b/crates/stc_ts_file_analyzer/tests/tsc/conformance/types/typeRelationships/subtypesAndSuperTypes/subtypingWithCallSignaturesWithRestParameters/3.ts
new file mode 100644
index 0000000000..722c610acc
--- /dev/null
+++ b/crates/stc_ts_file_analyzer/tests/tsc/conformance/types/typeRelationships/subtypesAndSuperTypes/subtypingWithCallSignaturesWithRestParameters/3.ts
@@ -0,0 +1,46 @@
+// call signatures in derived types must have the same or fewer optional parameters as the base type
+
+interface Base {
+ a: (...args: number[]) => number;
+ a2: (x: number, ...z: number[]) => number;
+ a3: (x: number, y?: string, ...z: number[]) => number;
+ a4: (x?: number, y?: string, ...z: number[]) => number;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+export interface I10E extends Base {
+ a3: (x: number, ...z: string[]) => number; // error
+}
+
+
+
+
+
+
+
+
diff --git a/crates/stc_ts_file_analyzer/tests/tsc/conformance/types/typeRelationships/subtypesAndSuperTypes/subtypingWithCallSignaturesWithRestParameters/3.tsc-errors.json b/crates/stc_ts_file_analyzer/tests/tsc/conformance/types/typeRelationships/subtypesAndSuperTypes/subtypingWithCallSignaturesWithRestParameters/3.tsc-errors.json
new file mode 100644
index 0000000000..4afda86b13
--- /dev/null
+++ b/crates/stc_ts_file_analyzer/tests/tsc/conformance/types/typeRelationships/subtypesAndSuperTypes/subtypingWithCallSignaturesWithRestParameters/3.tsc-errors.json
@@ -0,0 +1,8 @@
+[
+ {
+ "file": "tests/tsc/conformance/types/typeRelationships/subtypesAndSuperTypes/subtypingWithCallSignaturesWithRestParameters/3.ts",
+ "line": 36,
+ "col": 18,
+ "code": 2430
+ }
+]
\ No newline at end of file
diff --git a/crates/stc_ts_file_analyzer/tests/tsc/conformance/types/typeRelationships/subtypesAndSuperTypes/subtypingWithCallSignaturesWithRestParameters/4.ts b/crates/stc_ts_file_analyzer/tests/tsc/conformance/types/typeRelationships/subtypesAndSuperTypes/subtypingWithCallSignaturesWithRestParameters/4.ts
new file mode 100644
index 0000000000..d941fa50f1
--- /dev/null
+++ b/crates/stc_ts_file_analyzer/tests/tsc/conformance/types/typeRelationships/subtypesAndSuperTypes/subtypingWithCallSignaturesWithRestParameters/4.ts
@@ -0,0 +1,46 @@
+// call signatures in derived types must have the same or fewer optional parameters as the base type
+
+interface Base {
+ a: (...args: number[]) => number;
+ a2: (x: number, ...z: number[]) => number;
+ a3: (x: number, y?: string, ...z: number[]) => number;
+ a4: (x?: number, y?: string, ...z: number[]) => number;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+export interface I16 extends Base {
+ a4: (x: number, ...args: string[]) => number; // error, rest param has type mismatch
+}
+
+
diff --git a/crates/stc_ts_file_analyzer/tests/tsc/conformance/types/typeRelationships/subtypesAndSuperTypes/subtypingWithCallSignaturesWithRestParameters/4.tsc-errors.json b/crates/stc_ts_file_analyzer/tests/tsc/conformance/types/typeRelationships/subtypesAndSuperTypes/subtypingWithCallSignaturesWithRestParameters/4.tsc-errors.json
new file mode 100644
index 0000000000..4420d1afdf
--- /dev/null
+++ b/crates/stc_ts_file_analyzer/tests/tsc/conformance/types/typeRelationships/subtypesAndSuperTypes/subtypingWithCallSignaturesWithRestParameters/4.tsc-errors.json
@@ -0,0 +1,8 @@
+[
+ {
+ "file": "tests/tsc/conformance/types/typeRelationships/subtypesAndSuperTypes/subtypingWithCallSignaturesWithRestParameters/4.ts",
+ "line": 42,
+ "col": 18,
+ "code": 2430
+ }
+]
\ No newline at end of file
diff --git a/crates/stc_ts_file_analyzer/tests/tsc/conformance/types/typeRelationships/subtypesAndSuperTypes/subtypingWithCallSignaturesWithRestParameters/5.ts b/crates/stc_ts_file_analyzer/tests/tsc/conformance/types/typeRelationships/subtypesAndSuperTypes/subtypingWithCallSignaturesWithRestParameters/5.ts
new file mode 100644
index 0000000000..d4926d0687
--- /dev/null
+++ b/crates/stc_ts_file_analyzer/tests/tsc/conformance/types/typeRelationships/subtypesAndSuperTypes/subtypingWithCallSignaturesWithRestParameters/5.ts
@@ -0,0 +1,45 @@
+// call signatures in derived types must have the same or fewer optional parameters as the base type
+
+interface Base {
+ a: (...args: number[]) => number;
+ a2: (x: number, ...z: number[]) => number;
+ a3: (x: number, y?: string, ...z: number[]) => number;
+ a4: (x?: number, y?: string, ...z: number[]) => number;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+export interface I17 extends Base {
+ a4: (...args: number[]) => number; // error
+}
diff --git a/crates/stc_ts_file_analyzer/tests/tsc/conformance/types/typeRelationships/subtypesAndSuperTypes/subtypingWithCallSignaturesWithRestParameters/5.tsc-errors.json b/crates/stc_ts_file_analyzer/tests/tsc/conformance/types/typeRelationships/subtypesAndSuperTypes/subtypingWithCallSignaturesWithRestParameters/5.tsc-errors.json
new file mode 100644
index 0000000000..d103d8c6c8
--- /dev/null
+++ b/crates/stc_ts_file_analyzer/tests/tsc/conformance/types/typeRelationships/subtypesAndSuperTypes/subtypingWithCallSignaturesWithRestParameters/5.tsc-errors.json
@@ -0,0 +1,8 @@
+[
+ {
+ "file": "tests/tsc/conformance/types/typeRelationships/subtypesAndSuperTypes/subtypingWithCallSignaturesWithRestParameters/5.ts",
+ "line": 43,
+ "col": 18,
+ "code": 2430
+ }
+]
\ No newline at end of file
diff --git a/crates/stc_ts_types/src/lib.rs b/crates/stc_ts_types/src/lib.rs
index 9a4f8bf369..5b9137c832 100644
--- a/crates/stc_ts_types/src/lib.rs
+++ b/crates/stc_ts_types/src/lib.rs
@@ -3288,3 +3288,28 @@ impl_freeze!(Key);
impl_freeze!(Enum);
impl_freeze!(ClassDef);
impl_freeze!(Mapped);
+
+pub trait SpreadLike: 'static + Spanned + Clone {
+ fn is_spread(&self) -> bool;
+ fn ty(&self) -> &Type;
+}
+
+impl SpreadLike for FnParam {
+ fn is_spread(&self) -> bool {
+ matches!(&self.pat, RPat::Rest(..))
+ }
+
+ fn ty(&self) -> &Type {
+ &self.ty
+ }
+}
+
+impl SpreadLike for TypeOrSpread {
+ fn is_spread(&self) -> bool {
+ self.spread.is_some()
+ }
+
+ fn ty(&self) -> &Type {
+ &self.ty
+ }
+}
diff --git a/cspell.json b/cspell.json
index 0b9c4d6769..1fc6ce127e 100644
--- a/cspell.json
+++ b/cspell.json
@@ -57,6 +57,7 @@
"osascript",
"overriden",
"partialeq",
+ "Peekable",
"petgraph",
"pmutil",
"Postprocess",
@@ -125,4 +126,4 @@
"scripts/npm",
"**/stc_ts_testing/src/conformance.rs"
]
-}
\ No newline at end of file
+}