refactor: avoid hard error when inferring runtime type

This commit is contained in:
Evan You 2023-04-15 17:59:50 +08:00
parent a9f5e14c7c
commit 075498c959
4 changed files with 35 additions and 8 deletions

View File

@ -397,6 +397,11 @@ describe('resolveType', () => {
resolve(`import { X } from './foo'; defineProps<X>()`) resolve(`import { X } from './foo'; defineProps<X>()`)
).toThrow(`Failed to resolve import source "./foo" for type X`) ).toThrow(`Failed to resolve import source "./foo" for type X`)
}) })
test('should not error on unresolved type when inferring runtime type', () => {
expect(() => resolve(`defineProps<{ foo: T }>()`)).not.toThrow()
expect(() => resolve(`defineProps<{ foo: T['bar'] }>()`)).not.toThrow()
})
}) })
}) })

View File

@ -47,6 +47,13 @@ export interface SFCScriptBlock extends SFCBlock {
imports?: Record<string, ImportBinding> imports?: Record<string, ImportBinding>
scriptAst?: import('@babel/types').Statement[] scriptAst?: import('@babel/types').Statement[]
scriptSetupAst?: import('@babel/types').Statement[] scriptSetupAst?: import('@babel/types').Statement[]
warnings?: string[]
/**
* Fully resolved dependency file paths (unix slashes) with imported types
* used in macros, used for HMR cache busting in @vitejs/plugin-vue and
* vue-loader.
*/
deps?: string[]
} }
export interface SFCStyleBlock extends SFCBlock { export interface SFCStyleBlock extends SFCBlock {

View File

@ -7,7 +7,7 @@ import { PropsDestructureBindings } from './defineProps'
import { ModelDecl } from './defineModel' import { ModelDecl } from './defineModel'
import { BindingMetadata } from '../../../compiler-core/src' import { BindingMetadata } from '../../../compiler-core/src'
import MagicString from 'magic-string' import MagicString from 'magic-string'
import { TypeScope, WithScope } from './resolveType' import { TypeScope } from './resolveType'
export class ScriptCompileContext { export class ScriptCompileContext {
isJS: boolean isJS: boolean
@ -56,13 +56,17 @@ export class ScriptCompileContext {
// codegen // codegen
bindingMetadata: BindingMetadata = {} bindingMetadata: BindingMetadata = {}
helperImports: Set<string> = new Set() helperImports: Set<string> = new Set()
helper(key: string): string { helper(key: string): string {
this.helperImports.add(key) this.helperImports.add(key)
return `_${key}` return `_${key}`
} }
/**
* to be exposed on compiled script block for HMR cache busting
*/
deps?: string[]
constructor( constructor(
public descriptor: SFCDescriptor, public descriptor: SFCDescriptor,
public options: SFCScriptCompileOptions public options: SFCScriptCompileOptions
@ -125,7 +129,7 @@ export class ScriptCompileContext {
return block.content.slice(node.start!, node.end!) return block.content.slice(node.start!, node.end!)
} }
error(msg: string, node: Node & WithScope, scope?: TypeScope): never { error(msg: string, node: Node, scope?: TypeScope): never {
const offset = scope ? scope.offset : this.startOffset! const offset = scope ? scope.offset : this.startOffset!
throw new Error( throw new Error(
`[@vue/compiler-sfc] ${msg}\n\n${ `[@vue/compiler-sfc] ${msg}\n\n${

View File

@ -134,6 +134,7 @@ function innerResolveTypeElements(
break break
} }
} else { } else {
// TODO support `number` and `string` index type when possible
ctx.error( ctx.error(
`Unsupported index type: ${node.indexType.type}`, `Unsupported index type: ${node.indexType.type}`,
node.indexType, node.indexType,
@ -320,7 +321,11 @@ function resolveStringType(
case 'Uncapitalize': case 'Uncapitalize':
return getParam().map(s => s[0].toLowerCase() + s.slice(1)) return getParam().map(s => s[0].toLowerCase() + s.slice(1))
default: default:
ctx.error('Failed to resolve type reference', node, scope) ctx.error(
'Unsupported type when resolving string type',
node.typeName,
scope
)
} }
} }
} }
@ -906,7 +911,7 @@ export function inferRuntimeType(
if (node.typeName.type === 'Identifier') { if (node.typeName.type === 'Identifier') {
const resolved = resolveTypeReference(ctx, node, scope) const resolved = resolveTypeReference(ctx, node, scope)
if (resolved) { if (resolved) {
return inferRuntimeType(ctx, resolved, scope) return inferRuntimeType(ctx, resolved, resolved._ownerScope)
} }
switch (node.typeName.name) { switch (node.typeName.name) {
case 'Array': case 'Array':
@ -988,9 +993,15 @@ export function inferRuntimeType(
node.indexType.type === 'TSLiteralType' && node.indexType.type === 'TSLiteralType' &&
node.indexType.literal.type === 'StringLiteral' node.indexType.literal.type === 'StringLiteral'
) { ) {
const resolved = resolveTypeElements(ctx, node.objectType) try {
const key = node.indexType.literal.value const resolved = resolveTypeElements(ctx, node.objectType, scope)
return inferRuntimeType(ctx, resolved.props[key]) const key = node.indexType.literal.value
const prop = resolved.props[key]
return inferRuntimeType(ctx, prop, prop._ownerScope)
} catch (e) {
// avoid hard error, fallback to unknown
return [UNKNOWN_TYPE]
}
} }
} }