1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
use rnode::{Fold, FoldWith};
use stc_ts_types::{Array, ArrayMetadata, KeywordType, PropertySignature, Type};
use swc_common::TypeEq;
use swc_ecma_ast::TsKeywordTypeKind;

/// Type widener.
///
/// - Tuple => Array
/// - null => any
/// - undefined => any
pub struct Widen {
    pub tuple_to_array: bool,
}

impl Fold<Type> for Widen {
    fn fold(&mut self, mut ty: Type) -> Type {
        // TODO(kdy1): PERF
        ty.normalize_mut();
        let ty = ty.fold_children_with(self);

        match ty {
            Type::Keyword(
                ty @ KeywordType {
                    kind: TsKeywordTypeKind::TsNullKeyword | TsKeywordTypeKind::TsUndefinedKeyword,
                    ..
                },
            ) => Type::Keyword(KeywordType {
                kind: TsKeywordTypeKind::TsAnyKeyword,
                ..ty
            }),

            Type::Lit(..) => ty.force_generalize_top_level_literals(),

            Type::Tuple(tuple) if self.tuple_to_array => {
                let span = tuple.span;

                let mut types: Vec<Type> = vec![];

                for element in tuple.elems {
                    if types.iter().any(|item| item.type_eq(&element.ty)) {
                        continue;
                    }

                    types.push(*element.ty);
                }

                let elem_type = box Type::new_union(span, types);
                Type::Array(Array {
                    span,
                    elem_type,
                    metadata: ArrayMetadata {
                        common: tuple.metadata.common,
                        ..Default::default()
                    },
                    tracker: Default::default(),
                })
            }

            _ => ty,
        }
    }
}

impl Fold<PropertySignature> for Widen {
    fn fold(&mut self, mut value: PropertySignature) -> PropertySignature {
        value = value.fold_children_with(self);

        value.optional = true;

        value
    }
}