Skip to content

Commit

Permalink
feat(compiler-sfc): support string indexed type in macros
Browse files Browse the repository at this point in the history
  • Loading branch information
yyx990803 committed Apr 13, 2023
1 parent 51773d5 commit 3f779dd
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 12 deletions.
24 changes: 24 additions & 0 deletions packages/compiler-sfc/__tests__/compileScript/resolveType.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,30 @@ describe('resolveType', () => {
})
})

test('indexed access type', () => {
expect(
resolve(`
type T = { bar: number }
type S = { nested: { foo: T['bar'] }}
type Target = S['nested']
`).props
).toStrictEqual({
foo: ['Number']
})
})

// test('namespace', () => {
// expect(
// resolve(`
// type T = { foo: number, bar: string, baz: boolean }
// type K = 'foo' | 'bar'
// type Target = Omit<T, K>
// `).props
// ).toStrictEqual({
// baz: ['Boolean']
// })
// })

describe('errors', () => {
test('error on computed keys', () => {
expect(() => resolve(`type Target = { [Foo]: string }`)).toThrow(
Expand Down
67 changes: 55 additions & 12 deletions packages/compiler-sfc/src/script/resolveType.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {
Identifier,
Node,
Statement,
TSCallSignatureDeclaration,
Expand All @@ -8,6 +9,7 @@ import {
TSMappedType,
TSMethodSignature,
TSPropertySignature,
TSQualifiedName,
TSType,
TSTypeAnnotation,
TSTypeElement,
Expand Down Expand Up @@ -62,6 +64,34 @@ function innerResolveTypeElements(
case 'TSFunctionType': {
return { props: {}, calls: [node] }
}
case 'TSUnionType':
case 'TSIntersectionType':
return mergeElements(
node.types.map(t => resolveTypeElements(ctx, t)),
node.type
)
case 'TSMappedType':
return resolveMappedType(ctx, node)
case 'TSIndexedAccessType': {
if (
node.indexType.type === 'TSLiteralType' &&
node.indexType.literal.type === 'StringLiteral'
) {
const resolved = resolveTypeElements(ctx, node.objectType)
const key = node.indexType.literal.value
const targetType = resolved.props[key].typeAnnotation
if (targetType) {
return resolveTypeElements(ctx, targetType.typeAnnotation)
} else {
break
}
} else {
ctx.error(
`Unsupported index type: ${node.indexType.type}`,
node.indexType
)
}
}
case 'TSExpressionWithTypeArguments': // referenced by interface extends
case 'TSTypeReference': {
const resolved = resolveTypeReference(ctx, node)
Expand All @@ -82,16 +112,8 @@ function innerResolveTypeElements(
)
}
}
case 'TSUnionType':
case 'TSIntersectionType':
return mergeElements(
node.types.map(t => resolveTypeElements(ctx, t)),
node.type
)
case 'TSMappedType':
return resolveMappedType(ctx, node)
}
ctx.error(`Unsupported type in SFC macro: ${node.type}`, node)
ctx.error(`Unresolvable type in SFC macro: ${node.type}`, node)
}

function typeElementsToMap(
Expand Down Expand Up @@ -342,8 +364,15 @@ function getReferenceName(
if (ref.type === 'Identifier') {
return ref.name
} else {
// TODO qualified name, e.g. Foo.Bar
return []
return qualifiedNameToPath(ref)
}
}

function qualifiedNameToPath(node: Identifier | TSQualifiedName): string[] {
if (node.type === 'Identifier') {
return [node.name]
} else {
return [...qualifiedNameToPath(node.left), node.right.name]
}
}

Expand Down Expand Up @@ -376,8 +405,11 @@ function recordType(node: Node, types: Record<string, Node>) {
switch (node.type) {
case 'TSInterfaceDeclaration':
case 'TSEnumDeclaration':
types[node.id.name] = node
case 'TSModuleDeclaration': {
const id = node.id.type === 'Identifier' ? node.id.name : node.id.value
types[id] = node
break
}
case 'TSTypeAliasDeclaration':
types[node.id.name] = node.typeAnnotation
break
Expand Down Expand Up @@ -542,6 +574,17 @@ export function inferRuntimeType(
case 'TSSymbolKeyword':
return ['Symbol']

case 'TSIndexedAccessType': {
if (
node.indexType.type === 'TSLiteralType' &&
node.indexType.literal.type === 'StringLiteral'
) {
const resolved = resolveTypeElements(ctx, node.objectType)
const key = node.indexType.literal.value
return inferRuntimeType(ctx, resolved.props[key])
}
}

default:
return [UNKNOWN_TYPE] // no runtime check
}
Expand Down

0 comments on commit 3f779dd

Please sign in to comment.