Skip to content

Commit 8d919f8

Browse files
committed
fix(better-define): infer TS Extract&Exclude runtime type
discussion #285 vuejs/core#7339 vuejs/core#7337 vuejs/core#6252
1 parent 5b8b5f1 commit 8d919f8

File tree

4 files changed

+105
-2
lines changed

4 files changed

+105
-2
lines changed

.changeset/red-waves-tease.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'@vue-macros/better-define': patch
3+
'@vue-macros/api': patch
4+
---
5+
6+
infer TS `Extract` and `Exclude` runtime type

packages/api/src/vue/utils.ts

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,11 +67,36 @@ export async function inferRuntimeType(
6767
case 'Readonly':
6868
case 'Pick':
6969
case 'Omit':
70-
case 'Exclude':
71-
case 'Extract':
7270
case 'Required':
7371
case 'InstanceType':
7472
return ['Object']
73+
74+
case 'Extract':
75+
if (
76+
node.type.typeParameters &&
77+
node.type.typeParameters.params[1]
78+
) {
79+
const t = await resolveTSReferencedType({
80+
scope: node.scope,
81+
type: node.type.typeParameters.params[1],
82+
})
83+
if (isTSExports(t)) return ['Object']
84+
else if (t) return inferRuntimeType(t)
85+
}
86+
return ['null']
87+
case 'Exclude':
88+
if (
89+
node.type.typeParameters &&
90+
node.type.typeParameters.params[0]
91+
) {
92+
const t = await resolveTSReferencedType({
93+
scope: node.scope,
94+
type: node.type.typeParameters.params[0],
95+
})
96+
if (isTSExports(t)) return ['Object']
97+
else if (t) return inferRuntimeType(t)
98+
}
99+
return ['null']
75100
}
76101
}
77102
return [`null`]

packages/better-define/tests/__snapshots__/fixtures.test.ts.snap

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -586,6 +586,64 @@ export { specialKey as default };
586586
"
587587
`;
588588

589+
exports[`fixtures > tests/fixtures/ts-utility-types.vue > isProduction = false 1`] = `
590+
"import { defineComponent } from 'vue';
591+
592+
var _sfc_main = /* @__PURE__ */ defineComponent({
593+
__name: \\"ts-utility-types\\",
594+
props: {
595+
\\"foo\\": { type: String, required: true },
596+
\\"bar\\": { type: String, required: true }
597+
},
598+
setup(__props) {
599+
return () => {
600+
};
601+
}
602+
});
603+
604+
var _export_sfc = (sfc, props) => {
605+
const target = sfc.__vccOpts || sfc;
606+
for (const [key, val] of props) {
607+
target[key] = val;
608+
}
609+
return target;
610+
};
611+
612+
var tsUtilityTypes = /* @__PURE__ */ _export_sfc(_sfc_main, [__FILE__]);
613+
614+
export { tsUtilityTypes as default };
615+
"
616+
`;
617+
618+
exports[`fixtures > tests/fixtures/ts-utility-types.vue > isProduction = true 1`] = `
619+
"import { defineComponent } from 'vue';
620+
621+
var _sfc_main = /* @__PURE__ */ defineComponent({
622+
__name: \\"ts-utility-types\\",
623+
props: {
624+
\\"foo\\": null,
625+
\\"bar\\": null
626+
},
627+
setup(__props) {
628+
return () => {
629+
};
630+
}
631+
});
632+
633+
var _export_sfc = (sfc, props) => {
634+
const target = sfc.__vccOpts || sfc;
635+
for (const [key, val] of props) {
636+
target[key] = val;
637+
}
638+
return target;
639+
};
640+
641+
var tsUtilityTypes = /* @__PURE__ */ _export_sfc(_sfc_main, [__FILE__]);
642+
643+
export { tsUtilityTypes as default };
644+
"
645+
`;
646+
589647
exports[`fixtures > tests/fixtures/union.vue > isProduction = false 1`] = `
590648
"import { defineComponent } from 'vue';
591649
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<script setup lang="ts">
2+
type Union = '1' | '2' | '3'
3+
4+
type FooExtract = '1' | '2'
5+
type Foo = Extract<Union, FooExtract>
6+
7+
type BarExclude = '2'
8+
type Bar = Exclude<Union, BarExclude>
9+
10+
defineProps<{
11+
foo: Foo
12+
bar: Bar
13+
}>()
14+
</script>

0 commit comments

Comments
 (0)