From 83b47715e6e468163eafdd96c7b9cc332cf9e887 Mon Sep 17 00:00:00 2001 From: Josh Goldberg Date: Mon, 6 Feb 2023 04:53:18 -0500 Subject: [PATCH 1/2] Added failing test for mapped type --- src/types/utilities.test.ts | 26 ++++++++++++++++++++++++++ src/types/utilities.ts | 7 +++++-- 2 files changed, 31 insertions(+), 2 deletions(-) create mode 100644 src/types/utilities.test.ts diff --git a/src/types/utilities.test.ts b/src/types/utilities.test.ts new file mode 100644 index 00000000..5d7efc8b --- /dev/null +++ b/src/types/utilities.test.ts @@ -0,0 +1,26 @@ +import * as ts from "typescript"; +import { describe, expect, it } from "vitest"; + +import { createSourceFileAndTypeChecker } from "../test/utils"; +import { isPropertyReadonlyInType } from "./utilities"; + +describe("isPropertyReadonlyInType", () => { + it("does not crash when the type is a mapped type parameter extending any", () => { + const { sourceFile, typeChecker } = createSourceFileAndTypeChecker(` + type MyType = { + [K in keyof T]: 'cat' | 'dog' | T[K]; + }; + type Test = MyType; + `); + const node = sourceFile.statements.at(-1) as ts.TypeAliasDeclaration; + const type = typeChecker.getTypeAtLocation(node); + + expect( + isPropertyReadonlyInType( + type, + ts.escapeLeadingUnderscores("length"), + typeChecker + ) + ).toBe(false); + }); +}); diff --git a/src/types/utilities.ts b/src/types/utilities.ts index c7437993..d3a97045 100644 --- a/src/types/utilities.ts +++ b/src/types/utilities.ts @@ -92,8 +92,11 @@ function isReadonlyPropertyFromMappedType( !/^__@[^@]+$/.test(name as string) ) return declaration.readonlyToken.kind !== ts.SyntaxKind.MinusToken; - return isPropertyReadonlyInType( - (type as unknown as { modifiersType: ts.Type }).modifiersType, + + const { modifiersType } = type as { modifiersType?: ts.Type }; + + return /* modifiersType && */ isPropertyReadonlyInType( + modifiersType!, name, typeChecker ); From d64c9be7a8bfc18cbdc1e504271c10e328536809 Mon Sep 17 00:00:00 2001 From: Josh Goldberg Date: Mon, 6 Feb 2023 04:57:58 -0500 Subject: [PATCH 2/2] Fixed code to make the test pass --- src/types/utilities.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/types/utilities.ts b/src/types/utilities.ts index d3a97045..5237f4df 100644 --- a/src/types/utilities.ts +++ b/src/types/utilities.ts @@ -95,10 +95,8 @@ function isReadonlyPropertyFromMappedType( const { modifiersType } = type as { modifiersType?: ts.Type }; - return /* modifiersType && */ isPropertyReadonlyInType( - modifiersType!, - name, - typeChecker + return ( + modifiersType && isPropertyReadonlyInType(modifiersType, name, typeChecker) ); }