expect(deps && [...deps]).toStrictEqual(Object.keys(files))
})
+ test('relative import with indexed access type', () => {
+ const files = {
+ '/foo.ts': `
+ type Booleanish = boolean | 'true' | 'false';
+ export interface InputHTMLAttributes {
+ required?: Booleanish | undefined;
+ }
+ `,
+ }
+ const { props, deps } = resolve(
+ `
+ import { InputHTMLAttributes } from './foo.ts'
+ type ImportedType = InputHTMLAttributes['required']
+ defineProps<{
+ required: ImportedType,
+ }>()
+ `,
+ files,
+ )
+ expect(props).toStrictEqual({
+ required: ['Boolean', 'String', 'Unknown'],
+ })
+ expect(deps && [...deps]).toStrictEqual(Object.keys(files))
+ })
+
+ test('relative import with indexed access type with unresolvable extends', () => {
+ const files = {
+ '/foo.ts': `
+ type EventHandlers<E> = {
+ [K in keyof E]?: E[K] extends (...args: any) => any
+ ? E[K]
+ : (payload: E[K]) => void;
+ };
+ export interface Events {
+ onCopy: ClipboardEvent;
+ }
+ type Booleanish = boolean | 'true' | 'false';
+ export interface InputHTMLAttributes extends EventHandlers<Events>{
+ required?: Booleanish | undefined;
+ }
+ `,
+ }
+ const { props, deps } = resolve(
+ `
+ import { InputHTMLAttributes } from './foo.ts'
+ type ImportedType = InputHTMLAttributes['required']
+ defineProps<{
+ required: ImportedType,
+ }>()
+ `,
+ files,
+ )
+ expect(props).toStrictEqual({
+ required: ['Boolean', 'String', 'Unknown'],
+ })
+ expect(deps && [...deps]).toStrictEqual(Object.keys(files))
+ })
+
// #8339
test('relative, .js import', () => {
const files = {
// utils
| 'error'
+ | 'warn'
| 'helper'
| 'getString'
options: SimpleTypeResolveOptions
}
-export type TypeResolveContext = ScriptCompileContext | SimpleTypeResolveContext
+export type TypeResolveContext = (
+ | ScriptCompileContext
+ | SimpleTypeResolveContext
+) & {
+ silentOnExtendsFailure?: boolean
+}
type Import = Pick<ImportBinding, 'source' | 'imported'>
;(base.calls || (base.calls = [])).push(...calls)
}
} catch (e) {
- ctx.error(
- `Failed to resolve extends base type.\nIf this previously worked in 3.2, ` +
- `you can instruct the compiler to ignore this extend by adding ` +
- `/* @vue-ignore */ before it, for example:\n\n` +
- `interface Props extends /* @vue-ignore */ Base {}\n\n` +
- `Note: both in 3.2 or with the ignore, the properties in the base ` +
- `type are treated as fallthrough attrs at runtime.`,
- ext,
- scope,
- )
+ // when called from inferRuntimeType context, silently ignore extends
+ // resolution failure so that properties defined in the interface can
+ // still be correctly resolved
+ if (!ctx.silentOnExtendsFailure) {
+ ctx.error(
+ `Failed to resolve extends base type.\nIf this previously worked in 3.2, ` +
+ `you can instruct the compiler to ignore this extend by adding ` +
+ `/* @vue-ignore */ before it, for example:\n\n` +
+ `interface Props extends /* @vue-ignore */ Base {}\n\n` +
+ `Note: both in 3.2 or with the ignore, the properties in the base ` +
+ `type are treated as fallthrough attrs at runtime.`,
+ ext,
+ scope,
+ )
+ }
}
}
}
return [UNKNOWN_TYPE]
}
+ // set flag to silence extends resolution errors in this context
+ const prevSilent = ctx.silentOnExtendsFailure
+ ctx.silentOnExtendsFailure = true
+
try {
switch (node.type) {
case 'TSStringKeyword':
}
} catch (e) {
// always soft fail on failed runtime type inference
+ } finally {
+ ctx.silentOnExtendsFailure = prevSilent
}
return [UNKNOWN_TYPE] // no runtime check
}
typeParameters: Record<string, Node> | undefined = undefined,
): string[] {
if (types.length === 1) {
- return inferRuntimeType(ctx, types[0], scope, isKeyOf, typeParameters)
+ return inferRuntimeType(
+ ctx,
+ types[0],
+ (types[0] as MaybeWithScope)._ownerScope || scope,
+ isKeyOf,
+ typeParameters,
+ )
}
return [
...new Set(
([] as string[]).concat(
...types.map(t =>
- inferRuntimeType(ctx, t, scope, isKeyOf, typeParameters),
+ inferRuntimeType(
+ ctx,
+ t,
+ (t as MaybeWithScope)._ownerScope || scope,
+ isKeyOf,
+ typeParameters,
+ ),
),
),
),