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 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
#![allow(unused)]
use stc_ts_types::Type;
use swc_common::TypeEq;
use swc_ecma_ast::TsKeywordTypeKind;
use super::Analyzer;
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
pub(crate) enum Relation {
#[default]
Identity,
Assignable,
Comparable,
StrictSubtype,
}
#[derive(Debug, Default)]
struct IsRelatedData {}
impl Analyzer<'_, '_> {
/// Ported from `isTypeRelatedTo` of `tsc`.
pub(crate) fn is_type_related_to(&mut self, source: &Type, target: &Type, relation: Relation) -> bool {
let mut data = IsRelatedData::default();
self.is_type_related_to_inner(&mut data, source, target, relation)
}
fn is_type_related_to_inner(&mut self, data: &mut IsRelatedData, source: &Type, target: &Type, relation: Relation) -> bool {
if source.type_eq(target) {
return true;
}
if relation != Relation::Identity {
if relation == Relation::Comparable && !target.is_never() && self.is_simple_type_related_to(target, source, relation)
|| self.is_simple_type_related_to(source, target, relation)
{
return true;
}
}
if source.is_structured_or_instantiable() || target.is_structured_or_instantiable() {
return self.check_type_related_to(source, target, relation);
}
false
}
/// TODO: Implement
///
/// Ported from `isSimpleTypeRelatedTo` of `tsc`.
#[allow(clippy::nonminimal_bool)]
fn is_simple_type_related_to(&mut self, source: &Type, target: &Type, relation: Relation) -> bool {
let (s, t) = (source, target);
if t.is_any() || t.is_unknown() || s.is_never() {
return true;
}
if t.is_never() {
return false;
}
if s.is_str_like() && t.is_kwd(TsKeywordTypeKind::TsStringKeyword) {
return true;
}
// TODO
// if (s & TypeFlags.StringLiteral && s & TypeFlags.EnumLiteral &&
// t & TypeFlags.StringLiteral && !(t & TypeFlags.EnumLiteral) &&
// (source as StringLiteralType).value === (target as
// StringLiteralType).value) return true;
if s.is_num_like() && t.is_kwd(TsKeywordTypeKind::TsNumberKeyword) {
return true;
}
// TODO
// if (s & TypeFlags.NumberLiteral && s & TypeFlags.EnumLiteral &&
// t & TypeFlags.NumberLiteral && !(t & TypeFlags.EnumLiteral) &&
// (source as NumberLiteralType).value === (target as
// NumberLiteralType).value) return true;
if s.is_bigint_like() && t.is_kwd(TsKeywordTypeKind::TsBigIntKeyword) {
return true;
}
if s.is_bool_like() && t.is_kwd(TsKeywordTypeKind::TsBooleanKeyword) {
return true;
}
if s.is_symbol_like() && t.is_kwd(TsKeywordTypeKind::TsSymbolKeyword) {
return true;
}
// TODO
// if (s & TypeFlags.Enum && t & TypeFlags.Enum && source.symbol.escapedName ===
// target.symbol.escapedName && isEnumTypeRelatedTo(source.symbol,
// target.symbol, errorReporter)) return true;
// TODO
// if (s & TypeFlags.EnumLiteral && t & TypeFlags.EnumLiteral) {
// if (s & TypeFlags.Union && t & TypeFlags.Union &&
// isEnumTypeRelatedTo(source.symbol, target.symbol, errorReporter)) return
// true; if (s & TypeFlags.Literal && t & TypeFlags.Literal &&
// (source as LiteralType).value === (target as LiteralType).value &&
// isEnumTypeRelatedTo(source.symbol, target.symbol, errorReporter))
// return true; }
// In non-strictNullChecks mode, `undefined` and `null` are assignable to
// anything except `never`. Since unions and intersections may reduce to
// `never`, we exclude them here.
if s.is_undefined()
&& (!self.rule().strict_null_checks && !(t.is_union_type() || t.is_intersection())
|| (t.is_kwd(TsKeywordTypeKind::TsUndefinedKeyword) || t.is_kwd(TsKeywordTypeKind::TsVoidKeyword)))
{
return true;
}
if s.is_null() && (!self.rule().strict_null_checks && !(t.is_union_type() || t.is_intersection()) || t.is_null()) {
return true;
}
// TODO
// if (s & TypeFlags.Object && t & TypeFlags.NonPrimitive && !(relation ===
// strictSubtypeRelation && isEmptyAnonymousObjectType(source) &&
// !(getObjectFlags(source) & ObjectFlags.FreshLiteral))) return true;
if relation == Relation::Assignable || relation == Relation::Comparable {
if s.is_any() {
return true;
}
// Type number is assignable to any computed numeric enum type or
// any numeric enum literal type, and a numeric literal
// type is assignable any computed numeric enum type or any numeric
// enum literal type with a matching value. These rules
// exist such that enums can be used for bit-flag purposes.
// TODO
// if (s & TypeFlags.Number && (t & TypeFlags.Enum || t &
// TypeFlags.NumberLiteral && t & TypeFlags.EnumLiteral)) return
// true;
// TODO
// if (s & TypeFlags.NumberLiteral && !(s & TypeFlags.EnumLiteral)
// && (t & TypeFlags.Enum || t & TypeFlags.
// NumberLiteral && t & TypeFlags.EnumLiteral &&
// (source as NumberLiteralType).value === (target as
// NumberLiteralType).value)) return true;
// Anything is assignable to a union containing undefined, null, and
// {}
// TODO
// if (isUnknownLikeUnionType(target)) return true;
}
false
}
/// TODO: Implement
///
/// Ported from `checkTypeRelatedTo` of `tsc`.
fn check_type_related_to(&mut self, source: &Type, target: &Type, relation: Relation) -> bool {
false
}
}