Skip to content

Commit

Permalink
feat(api): support mapped type parameters
Browse files Browse the repository at this point in the history
  • Loading branch information
mxsdev committed Oct 8, 2022
1 parent 7dfbeb8 commit d0c603a
Show file tree
Hide file tree
Showing 8 changed files with 54 additions and 26 deletions.
25 changes: 14 additions & 11 deletions packages/api/src/tree.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import assert from "assert";
import ts from "typescript";
import { IndexInfo, SignatureInfo, SymbolInfo, TypeId, TypeInfo, TypeInfoNoId, TypeParameterInfo } from "./types";
import { getIntersectionTypesFlat, getSignaturesOfType, getSymbolType, getTypeId, isPureObject, wrapSafe } from "./util";
import { getIndexInfos, getIntersectionTypesFlat, getSignaturesOfType, getSymbolType, getTypeId, TSIndexInfoMerged, isPureObject, wrapSafe } from "./util";

// TODO: need to add max depth

Expand Down Expand Up @@ -43,7 +43,9 @@ export function generateTypeTree({ symbol, type }: {symbol: ts.Symbol, type?: un
function _generateTypeTree(typeChecker: ts.TypeChecker, type: ts.Type, ctx: TypeTreeContext): TypeInfoNoId {
const flags = type.getFlags()

if(flags & ts.TypeFlags.Any) { return { kind: 'primitive', primitive: 'any' }}
if(flags & ts.TypeFlags.TypeParameter) {
return { kind: 'type_parameter'}
} else if(flags & ts.TypeFlags.Any) { return { kind: 'primitive', primitive: 'any' }}
else if(flags & ts.TypeFlags.Unknown) { return { kind: 'primitive', primitive: 'unknown' }}
else if(flags & ts.TypeFlags.Undefined) { return { kind: 'primitive', primitive: 'undefined' }}
else if(flags & ts.TypeFlags.Null) { return { kind: 'primitive', primitive: 'null' }}
Expand All @@ -64,16 +66,13 @@ function _generateTypeTree(typeChecker: ts.TypeChecker, type: ts.Type, ctx: Type
// TODO: add enum info???
else if(flags & ts.TypeFlags.BigIntLiteral) { return { kind: 'bigint_literal', value: (type as ts.BigIntLiteralType).value }}
// TODO: add type param info
else if(flags & ts.TypeFlags.TypeParameter) {

}
else if(flags & ts.TypeFlags.Object) {
// TODO: arrays
return {
kind: 'object',
signatures: getSignaturesOfType(typeChecker, type).map(sig => getSignatureInfo(sig, ctx)),
properties: type.getProperties().map(typeTreeSymb),
indexInfos: typeChecker.getIndexInfosOfType(type).map(indexInfo => getIndexInfo(indexInfo, ctx))
indexInfos: getIndexInfos(typeChecker, type).map(indexInfo => getIndexInfo(indexInfo, ctx))
}
} else if(flags & ts.TypeFlags.Union) {
return {
Expand Down Expand Up @@ -145,13 +144,14 @@ function getSignatureInfo(signature: ts.Signature, ctx: TypeTreeContext): Signat
}
}

function getIndexInfo(indexInfo: ts.IndexInfo, ctx: TypeTreeContext): IndexInfo {
function getIndexInfo(indexInfo: TSIndexInfoMerged, ctx: TypeTreeContext): IndexInfo {
const { typeChecker } = ctx

return {
keyType: generateTypeTree({ type: indexInfo.keyType }, ctx),
type: generateTypeTree({ type: indexInfo.type }, ctx),
parameterSymbol: wrapSafe(getSymbolInfo)(wrapSafe(typeChecker.getSymbolAtLocation)(indexInfo.declaration?.parameters[0]))
...indexInfo.keyType ? { keyType: generateTypeTree({ type: indexInfo.keyType }, ctx) } : { },
...indexInfo.type ? { type: generateTypeTree({ type: indexInfo.type }, ctx) } : { },
// @ts-expect-error
parameterSymbol: wrapSafe(getSymbolInfo)(wrapSafe(typeChecker.getSymbolAtLocation)(indexInfo?.declaration?.parameters?.[0]))
}
}

Expand All @@ -168,7 +168,10 @@ export function getTypeInfoChildren(info: TypeInfo): TypeInfo[] {
return [
...info.properties,
...info.signatures?.flatMap(s => [...s.parameters, s.returnType]) ?? [],
...info.indexInfos?.map(x => x.type) ?? [],
...info.indexInfos?.flatMap(x => [
...(x.type ? [x.type] : []),
...(x.keyType ? [x.keyType] : []),
]) ?? [],
// TODO: array
]
}
Expand Down
4 changes: 2 additions & 2 deletions packages/api/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ export type SymbolInfo = {
}

export type IndexInfo = {
keyType: TypeInfo,
type: TypeInfo,
keyType?: TypeInfo,
type?: TypeInfo,
parameterSymbol?: SymbolInfo
}

Expand Down
27 changes: 26 additions & 1 deletion packages/api/src/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,33 @@ export function getSignaturesOfType(typeChecker: ts.TypeChecker, type: ts.Type)
]
}

export type TSIndexInfoMerged = { declaration?: ts.MappedTypeNode|ts.IndexSignatureDeclaration, keyType?: ts.Type, type?: ts.Type, parameterType?: ts.Type }
interface MappedType extends ts.Type {
declaration: ts.MappedTypeNode;
typeParameter?: ts.TypeParameter;
constraintType?: ts.Type;
// nameType?: ts.Type;
templateType?: ts.Type;
modifiersType?: ts.Type;
// resolvedApparentType?: ts.Type;
// containsError?: boolean;
}

export function getIndexInfos(typeChecker: ts.TypeChecker, type: ts.Type) {
return typeChecker.getIndexInfosOfType(type)
const indexInfos: TSIndexInfoMerged[] = [ ...typeChecker.getIndexInfosOfType(type) ]

if((type.flags & ts.TypeFlags.Object) && ((type as ObjectType).objectFlags & ts.ObjectFlags.Mapped)) {
const mappedType = type as MappedType

indexInfos.push({
keyType: mappedType.constraintType,
type: mappedType.templateType,
parameterType: mappedType.typeParameter,
declaration: mappedType.declaration
})
}

return indexInfos
}

export function createType(checker: ts.TypeChecker, flags: ts.TypeFlags) {
Expand Down
2 changes: 1 addition & 1 deletion tests/baselines/reference/mapped.tree
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
=== mapped.ts ===

type mapped = { [index: string]: number }
> mapped --- {"kind":"object","signatures":[],"properties":[],"indexInfos":[{"keyType":{"kind":"primitive","primitive":"string","id":15},"type":{"kind":"primitive","primitive":"number","id":16}}],"symbolMeta":{"name":"mapped","flags":524288},"id":86}
> mapped --- {"kind":"object","signatures":[],"properties":[],"indexInfos":[{"keyType":{"kind":"primitive","primitive":"number","id":16}}],"symbolMeta":{"name":"mapped","flags":524288},"id":86}
> { [index: string]: number }
> [index: string]: number
> [index: string]: number
Expand Down
2 changes: 1 addition & 1 deletion tests/baselines/reference/partial.merged.types
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
type partialUnion = Partial<{a: string}|{b: string}>
> partialUnion --- { a?: string; } | { b?: string; }
> Partial<{a: string}|{b: string}>
> Partial --- {}
> Partial --- { [P in keyof T]?: T[P]; }
> {a: string}|{b: string}
> {a: string}|{b: string}
> {a: string}|{b: string}
Expand Down
4 changes: 2 additions & 2 deletions tests/baselines/reference/partial.tree
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
=== partial.ts ===

type partialUnion = Partial<{a: string}|{b: string}>
> partialUnion --- {"kind":"union","types":[{"kind":"object","signatures":[],"properties":[{"kind":"primitive","primitive":"string","symbolMeta":{"name":"a","flags":50331652},"id":15}],"indexInfos":[],"symbolMeta":{"name":"__type","flags":2048},"id":93},{"kind":"object","signatures":[],"properties":[{"kind":"reference","symbolMeta":{"name":"b","flags":50331652},"id":15}],"indexInfos":[],"symbolMeta":{"name":"__type","flags":2048},"id":95}],"symbolMeta":{"name":"partialUnion","flags":524288},"id":97}
> partialUnion --- {"kind":"union","types":[{"kind":"object","signatures":[],"properties":[{"kind":"primitive","primitive":"string","symbolMeta":{"name":"a","flags":50331652},"id":15}],"indexInfos":[{"keyType":{"kind":"string_literal","value":"a","id":98}}],"symbolMeta":{"name":"__type","flags":2048},"id":93},{"kind":"object","signatures":[],"properties":[{"kind":"reference","symbolMeta":{"name":"b","flags":50331652},"id":15}],"indexInfos":[{"keyType":{"kind":"string_literal","value":"b","id":100}}],"symbolMeta":{"name":"__type","flags":2048},"id":95}],"symbolMeta":{"name":"partialUnion","flags":524288},"id":97}
> Partial<{a: string}|{b: string}>
> Partial --- {"kind":"object","signatures":[],"properties":[],"indexInfos":[],"symbolMeta":{"name":"Partial","flags":524288},"id":86}
> Partial --- {"kind":"object","signatures":[],"properties":[],"indexInfos":[{"keyType":{"kind":"index","indexOf":{"kind":"type_parameter","symbolMeta":{"name":"T","flags":262144},"id":87},"id":89},"type":{"kind":"indexed_access","indexType":{"kind":"type_parameter","symbolMeta":{"name":"P","flags":262144},"id":88},"objectType":{"kind":"reference","symbolMeta":{"name":"T","flags":262144},"id":87},"id":99}}],"symbolMeta":{"name":"Partial","flags":524288},"id":86}
> {a: string}|{b: string}
> {a: string}|{b: string}
> {a: string}|{b: string}
Expand Down
8 changes: 4 additions & 4 deletions tests/baselines/reference/pick.merged.types
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@ type t = { a: "b", c: "d", d: { a: "b" } }
> a --- "b"

type p = Pick<t, "a"|"d"> & {b: "asd", d: { b: "c" }}
> p --- { d: { a: "b"; b: "c"; }; a: "b"; b: "asd"; }
> p --- { b: "asd"; d: { b: "c"; }; } & Pick<t, "d" | "a">
> Pick<t, "a"|"d"> & {b: "asd", d: { b: "c" }}
> Pick<t, "a"|"d"> & {b: "asd", d: { b: "c" }}
> Pick<t, "a"|"d">
> Pick --- {}
> Pick --- { [P in K]: T[P]; }
> t, "a"|"d"
> t
> t --- { a: "b"; c: "d"; d: { a: "b"; }; }
Expand All @@ -39,9 +39,9 @@ const test3: p = {a: "b", b: "asd", d: { a: "b", b: "c" }}
> const test3: p = {a: "b", b: "asd", d: { a: "b", b: "c" }}
> test3: p = {a: "b", b: "asd", d: { a: "b", b: "c" }}
> test3: p = {a: "b", b: "asd", d: { a: "b", b: "c" }}
> test3 --- { d: { a: "b"; b: "c"; }; a: "b"; b: "asd"; }
> test3 --- { b: "asd"; d: { b: "c"; }; } & Pick<t, "d" | "a">
> p
> p --- { d: { a: "b"; b: "c"; }; a: "b"; b: "asd"; }
> p --- { b: "asd"; d: { b: "c"; }; } & Pick<t, "d" | "a">
> {a: "b", b: "asd", d: { a: "b", b: "c" }}
> a: "b", b: "asd", d: { a: "b", b: "c" }
> a: "b"
Expand Down
8 changes: 4 additions & 4 deletions tests/baselines/reference/pick.tree
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@ type t = { a: "b", c: "d", d: { a: "b" } }
> a --- {"kind":"string_literal","value":"b","symbolMeta":{"name":"a","flags":4},"id":87}

type p = Pick<t, "a"|"d"> & {b: "asd", d: { b: "c" }}
> p --- {"kind":"object","properties":[{"kind":"object","properties":[{"kind":"string_literal","value":"b","symbolMeta":{"name":"a","flags":4},"id":87},{"kind":"string_literal","value":"c","symbolMeta":{"name":"b","flags":4},"id":107}],"symbolMeta":{"name":"d","flags":33554436},"id":106},{"kind":"reference","symbolMeta":{"name":"a","flags":33554436},"id":87},{"kind":"string_literal","value":"asd","symbolMeta":{"name":"b","flags":4},"id":109}],"symbolMeta":{"name":"p","flags":524288},"id":103}
> p --- {"kind":"intersection","types":[{"kind":"object","signatures":[],"properties":[{"kind":"object","signatures":[],"properties":[{"kind":"string_literal","value":"b","symbolMeta":{"name":"a","flags":4},"id":87}],"indexInfos":[],"symbolMeta":{"name":"d","flags":33554436},"id":91},{"kind":"reference","symbolMeta":{"name":"a","flags":33554436},"id":87}],"indexInfos":[{"keyType":{"kind":"union","types":[{"kind":"string_literal","value":"d","id":89},{"kind":"string_literal","value":"a","id":97}],"id":99}}],"symbolMeta":{"name":"__type","flags":2048},"id":100}],"properties":[{"kind":"object","properties":[{"kind":"reference","symbolMeta":{"name":"a","flags":4},"id":87},{"kind":"string_literal","value":"c","symbolMeta":{"name":"b","flags":4},"id":107}],"symbolMeta":{"name":"d","flags":33554436},"id":106},{"kind":"reference","symbolMeta":{"name":"a","flags":33554436},"id":87},{"kind":"string_literal","value":"asd","symbolMeta":{"name":"b","flags":4},"id":109}],"symbolMeta":{"name":"p","flags":524288},"id":103}
> Pick<t, "a"|"d"> & {b: "asd", d: { b: "c" }}
> Pick<t, "a"|"d"> & {b: "asd", d: { b: "c" }}
> Pick<t, "a"|"d">
> Pick --- {"kind":"object","signatures":[],"properties":[],"indexInfos":[],"symbolMeta":{"name":"Pick","flags":524288},"id":92}
> Pick --- {"kind":"object","signatures":[],"properties":[],"indexInfos":[{"keyType":{"kind":"type_parameter","symbolMeta":{"name":"K","flags":262144},"id":94},"type":{"kind":"indexed_access","indexType":{"kind":"type_parameter","symbolMeta":{"name":"P","flags":262144},"id":95},"objectType":{"kind":"type_parameter","symbolMeta":{"name":"T","flags":262144},"id":93},"id":104}}],"symbolMeta":{"name":"Pick","flags":524288},"id":92}
> t, "a"|"d"
> t
> t --- {"kind":"object","signatures":[],"properties":[{"kind":"string_literal","value":"b","symbolMeta":{"name":"a","flags":4},"id":87},{"kind":"string_literal","value":"d","symbolMeta":{"name":"c","flags":4},"id":89},{"kind":"object","signatures":[],"properties":[{"kind":"reference","symbolMeta":{"name":"a","flags":4},"id":87}],"indexInfos":[],"symbolMeta":{"name":"d","flags":4},"id":91}],"indexInfos":[],"symbolMeta":{"name":"t","flags":524288},"id":86}
Expand All @@ -39,9 +39,9 @@ const test3: p = {a: "b", b: "asd", d: { a: "b", b: "c" }}
> const test3: p = {a: "b", b: "asd", d: { a: "b", b: "c" }}
> test3: p = {a: "b", b: "asd", d: { a: "b", b: "c" }}
> test3: p = {a: "b", b: "asd", d: { a: "b", b: "c" }}
> test3 --- {"kind":"object","properties":[{"kind":"object","properties":[{"kind":"string_literal","value":"b","symbolMeta":{"name":"a","flags":4},"id":87},{"kind":"string_literal","value":"c","symbolMeta":{"name":"b","flags":4},"id":107}],"symbolMeta":{"name":"d","flags":33554436},"id":106},{"kind":"reference","symbolMeta":{"name":"a","flags":33554436},"id":87},{"kind":"string_literal","value":"asd","symbolMeta":{"name":"b","flags":4},"id":109}],"symbolMeta":{"name":"test3","flags":2},"id":103}
> test3 --- {"kind":"intersection","types":[{"kind":"object","signatures":[],"properties":[{"kind":"object","signatures":[],"properties":[{"kind":"string_literal","value":"b","symbolMeta":{"name":"a","flags":4},"id":87}],"indexInfos":[],"symbolMeta":{"name":"d","flags":33554436},"id":91},{"kind":"reference","symbolMeta":{"name":"a","flags":33554436},"id":87}],"indexInfos":[{"keyType":{"kind":"union","types":[{"kind":"string_literal","value":"d","id":89},{"kind":"string_literal","value":"a","id":97}],"id":99}}],"symbolMeta":{"name":"__type","flags":2048},"id":100}],"properties":[{"kind":"object","properties":[{"kind":"reference","symbolMeta":{"name":"a","flags":4},"id":87},{"kind":"string_literal","value":"c","symbolMeta":{"name":"b","flags":4},"id":107}],"symbolMeta":{"name":"d","flags":33554436},"id":106},{"kind":"reference","symbolMeta":{"name":"a","flags":33554436},"id":87},{"kind":"string_literal","value":"asd","symbolMeta":{"name":"b","flags":4},"id":109}],"symbolMeta":{"name":"test3","flags":2},"id":103}
> p
> p --- {"kind":"object","properties":[{"kind":"object","properties":[{"kind":"string_literal","value":"b","symbolMeta":{"name":"a","flags":4},"id":87},{"kind":"string_literal","value":"c","symbolMeta":{"name":"b","flags":4},"id":107}],"symbolMeta":{"name":"d","flags":33554436},"id":106},{"kind":"reference","symbolMeta":{"name":"a","flags":33554436},"id":87},{"kind":"string_literal","value":"asd","symbolMeta":{"name":"b","flags":4},"id":109}],"symbolMeta":{"name":"p","flags":524288},"id":103}
> p --- {"kind":"intersection","types":[{"kind":"object","signatures":[],"properties":[{"kind":"object","signatures":[],"properties":[{"kind":"string_literal","value":"b","symbolMeta":{"name":"a","flags":4},"id":87}],"indexInfos":[],"symbolMeta":{"name":"d","flags":33554436},"id":91},{"kind":"reference","symbolMeta":{"name":"a","flags":33554436},"id":87}],"indexInfos":[{"keyType":{"kind":"union","types":[{"kind":"string_literal","value":"d","id":89},{"kind":"string_literal","value":"a","id":97}],"id":99}}],"symbolMeta":{"name":"__type","flags":2048},"id":100}],"properties":[{"kind":"object","properties":[{"kind":"reference","symbolMeta":{"name":"a","flags":4},"id":87},{"kind":"string_literal","value":"c","symbolMeta":{"name":"b","flags":4},"id":107}],"symbolMeta":{"name":"d","flags":33554436},"id":106},{"kind":"reference","symbolMeta":{"name":"a","flags":33554436},"id":87},{"kind":"string_literal","value":"asd","symbolMeta":{"name":"b","flags":4},"id":109}],"symbolMeta":{"name":"p","flags":524288},"id":103}
> {a: "b", b: "asd", d: { a: "b", b: "c" }}
> a: "b", b: "asd", d: { a: "b", b: "c" }
> a: "b"
Expand Down

0 comments on commit d0c603a

Please sign in to comment.