Handle enums while reducing intersections
https://github.com/dudykr/stc/blob/2c2c8224273ffbca0aba723b34fd560b6b4a3c45/crates/stc_ts_file_analyzer/tests/pass/types/intersection/intersectionReduction/.4.ts#L3-L10
https://github.com/dudykr/stc/blob/2c2c8224273ffbca0aba723b34fd560b6b4a3c45/crates/stc_ts_file_analyzer/tests/pass/types/intersection/intersectionReduction/.5.ts#L3-L10
In the files above, the assignment should succeed because Tag1 and Tag2 are enum without an initializer, and enums without initializers are numbers while reducing.
This can be done by checking for enums in https://github.com/dudykr/stc/blob/2c2c8224273ffbca0aba723b34fd560b6b4a3c45/crates/stc_ts_file_analyzer/src/analyzer/types/mod.rs#L666-L693
Hi @kdy1, I'd love to take a shot at this!
Cool, thanks!
@kdy1 could you help point me in the right direction? (I'm fairly new to this type of thing). From what I understand I should check if the type is an empty enum on line 688.
@samiam376 You can use expand_enum_variant to convert an enum to a literal.
https://github.com/dudykr/stc/blob/2ab93ad46cd2683539300bde8f30c7bf89ac1e15/crates/stc_ts_file_analyzer/src/analyzer/enums.rs#L565-L604
@kdy1 where should I be calling that function?
@samiam376 https://github.com/dudykr/stc/blob/2c2c8224273ffbca0aba723b34fd560b6b4a3c45/crates/stc_ts_file_analyzer/src/analyzer/types/mod.rs#L666-L693
I already posted it on the issue
@kdy1 this is what I've been trying to too. Could you tell me if I'm headed in the right direction?
pub(crate) fn normalize_intersection_types(&mut self, span: Span, types: &[Type], opts: NormalizeTypeOpts) -> VResult<Option<Type>> {
macro_rules! never {
() => {{
Ok(Some(Type::Keyword(KeywordType {
span,
kind: TsKeywordTypeKind::TsNeverKeyword,
metadata: KeywordTypeMetadata { ..Default::default() },
})))
}};
}
let is_str = types.iter().any(|ty| ty.is_str());
let is_num = types.iter().any(|ty| ty.is_num());
let is_bool = types.iter().any(|ty| ty.is_bool());
let is_empty_enum = types.iter().any(|ty| match ty.normalize() {
Type::Enum(ty_enum) => ty_enum.members.len() == 0,
_ => false,
});
if u32::from(is_str) + u32::from(is_num) + u32::from(is_bool) + u32::from(is_empty_enum) >= 2 {
return never!();
}
if !self.rule().always_strict && types.len() == 2 {
let (a, b) = (&types[0], &types[1]);
let a_expanded = self.expand_enum_variant(a.to_owned()).unwrap();
let b_expanded = self.expand_enum_variant(b.to_owned()).unwrap();
if (a_expanded.is_str_lit() && b_expanded.is_str_lit()
|| (a_expanded.is_num_lit() && b_expanded.is_num_lit())
|| (a_expanded.is_bool_lit() && b_expanded.is_bool_lit()))
&& !a_expanded.type_eq(&b_expanded)
{
return never!();
}
}
No, you should check for Type::EnumVariant, and based on the enum name, you should check if the enum is numeric (empty, no initializer, or numeric initializer)