From d3f1f175dcdac4e7204eaa296ba94b2bd197ec8c Mon Sep 17 00:00:00 2001 From: EduardoRFS Date: Wed, 7 Aug 2019 20:48:25 -0300 Subject: [PATCH] $ExpectType accept generics with default type --- src/rules/expectRule.ts | 42 ++++++++++++++++++++++++++++++---- test/expect/expectType.ts.lint | 7 +++++- 2 files changed, 44 insertions(+), 5 deletions(-) diff --git a/src/rules/expectRule.ts b/src/rules/expectRule.ts index 999ecbb3..838b182a 100644 --- a/src/rules/expectRule.ts +++ b/src/rules/expectRule.ts @@ -298,6 +298,38 @@ interface ExpectTypeFailures { readonly unusedAssertions: Iterable; } +function typeToString (checker: TsType.TypeChecker, type: TsType.Type) { + return checker.typeToString(type, /*enclosingDeclaration*/ undefined, TsType.TypeFormatFlags.NoTruncation); +} +function matchGenericDefault(checker: TsType.TypeChecker, type: TsType.Type, expected: string) { + const typeStr = typeToString(checker, type); + + const ref = type as TsType.TypeReference; + const args = ref.typeArguments; + const generic = ref.target; + + if (!generic || !generic.typeArguments || !typeStr.startsWith(expected)) { + return false; + } + + const defaults = generic.typeArguments + .map(type => type.getDefault() as TsType.Type) + .filter(Boolean); + + // store + ref.typeArguments = defaults; + + if ( + defaults.length !== generic.typeArguments.length || + typeStr !== typeToString(checker, ref) + ) { + return false; + } + // reset + ref.typeArguments = args; + + return true; +} function matchReadonlyArray(actual: string, expected: string) { if (!(/\breadonly\b/.test(actual) && /\bReadonlyArray\b/.test(expected))) return false; const readonlyArrayRegExp = /\bReadonlyArray \ No newline at end of file +ar; // $ExpectType ReadonlyArray + +// Test generic default +declare interface GenericWithDefault {} +declare const genericWithDefault: GenericWithDefault; +genericWithDefault; // $ExpectType GenericWithDefault \ No newline at end of file