Skip to content

Commit 0ab27f2

Browse files
committed
fix(types): support inferring inject
1 parent a9ca2d8 commit 0ab27f2

File tree

6 files changed

+320
-40
lines changed

6 files changed

+320
-40
lines changed

types/common.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ export type UnionToIntersection<U> = (
55
) extends (k: infer I) => void
66
? I
77
: never
8-
8+
99
// Conditional returns can enforce identical types.
1010
// See here: https://github.com/Microsoft/TypeScript/issues/27024#issuecomment-421529650
1111
// prettier-ignore

types/options.d.ts

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,9 @@ export interface ComponentOptions<
174174
Props = DefaultProps,
175175
RawBindings = {},
176176
Mixin extends ComponentOptionsMixin = ComponentOptionsMixin,
177-
Extends extends ComponentOptionsMixin = ComponentOptionsMixin
177+
Extends extends ComponentOptionsMixin = ComponentOptionsMixin,
178+
Inject extends InjectOptions = {},
179+
InjectNames extends string = string,
178180
> {
179181
data?: Data
180182
props?: PropsDef
@@ -225,7 +227,7 @@ export interface ComponentOptions<
225227
filters?: { [key: string]: Function }
226228

227229
provide?: object | (() => object)
228-
inject?: InjectOptions
230+
inject?: Inject | InjectNames[]
229231

230232
model?: {
231233
prop?: string
@@ -342,8 +344,20 @@ export interface DirectiveOptions {
342344

343345
export type InjectKey = string | symbol
344346

345-
export type InjectOptions =
346-
| {
347-
[key: string]: InjectKey | { from?: InjectKey; default?: any }
348-
}
349-
| string[]
347+
export type InjectOptions = string[] | ObjectInjectOptions
348+
349+
type ObjectInjectOptions = Record<
350+
InjectKey,
351+
string | symbol | { from?: string | symbol; default?: unknown }
352+
>
353+
354+
export type InjectToObject<T extends InjectOptions> =
355+
T extends string[]
356+
? {
357+
[K in T[number]]?: unknown
358+
}
359+
: T extends ObjectInjectOptions
360+
? {
361+
[K in keyof T]?: unknown
362+
}
363+
: never

types/test/v3/define-component-test.tsx

Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1225,3 +1225,210 @@ describe('should report non-existent properties in instance', () => {
12251225
// @ts-expect-error
12261226
instance2.foo
12271227
})
1228+
1229+
1230+
describe('inject', () => {
1231+
test('with object inject', () => {
1232+
defineComponent({
1233+
props: {
1234+
a: String
1235+
},
1236+
inject: {
1237+
foo: 'foo',
1238+
bar: 'bar',
1239+
},
1240+
created() {
1241+
expectType<unknown>(this.foo)
1242+
expectType<unknown>(this.bar)
1243+
// @ts-expect-error
1244+
expectError(this.foobar = 1)
1245+
}
1246+
})
1247+
})
1248+
1249+
test('with array inject', () => {
1250+
defineComponent({
1251+
props: ['a', 'b'],
1252+
inject: ['foo', 'bar'],
1253+
created() {
1254+
expectType<unknown>(this.foo)
1255+
expectType<unknown>(this.bar)
1256+
// @ts-expect-error
1257+
expectError(this.foobar = 1)
1258+
}
1259+
})
1260+
})
1261+
1262+
test('with no props', () => {
1263+
defineComponent({
1264+
inject: {
1265+
foo: {
1266+
from: 'pfoo',
1267+
default: 'foo'
1268+
},
1269+
bar: {
1270+
from: 'pbar',
1271+
default: 'bar'
1272+
},
1273+
},
1274+
created() {
1275+
expectType<unknown>(this.foo)
1276+
expectType<unknown>(this.bar)
1277+
// @ts-expect-error
1278+
expectError(this.foobar = 1)
1279+
}
1280+
})
1281+
})
1282+
1283+
test('without inject', () => {
1284+
defineComponent({
1285+
props: ['a', 'b'],
1286+
created() {
1287+
// @ts-expect-error
1288+
expectError(this.foo = 1)
1289+
// @ts-expect-error
1290+
expectError(this.bar = 1)
1291+
}
1292+
})
1293+
})
1294+
1295+
test('define mixins w/ no props', () => {
1296+
const MixinA = defineComponent({
1297+
inject: {
1298+
foo: 'foo'
1299+
},
1300+
})
1301+
const MixinB = defineComponent({
1302+
inject: ['bar'],
1303+
})
1304+
// with no props
1305+
defineComponent({
1306+
mixins: [MixinA, MixinB],
1307+
created() {
1308+
expectType<unknown>(this.foo)
1309+
expectType<unknown>(this.bar)
1310+
}
1311+
})
1312+
// with object props
1313+
defineComponent({
1314+
mixins: [MixinA, MixinB],
1315+
props: {
1316+
baz: {
1317+
type: Number,
1318+
required: true
1319+
}
1320+
},
1321+
created() {
1322+
expectType<unknown>(this.foo)
1323+
expectType<unknown>(this.bar)
1324+
expectType<number>(this.baz)
1325+
}
1326+
})
1327+
// with array props
1328+
defineComponent({
1329+
mixins: [MixinA, MixinB],
1330+
props: ['baz'],
1331+
created() {
1332+
expectType<unknown>(this.foo)
1333+
expectType<unknown>(this.bar)
1334+
expectType<any>(this.baz)
1335+
}
1336+
})
1337+
})
1338+
1339+
test('define mixins w/ object props', () => {
1340+
const MixinA = defineComponent({
1341+
props: {
1342+
a: String
1343+
},
1344+
inject: {
1345+
foo: 'foo'
1346+
},
1347+
})
1348+
const MixinB = defineComponent({
1349+
props: {
1350+
b: String
1351+
},
1352+
inject: ['bar'],
1353+
})
1354+
// with no props
1355+
defineComponent({
1356+
mixins: [MixinA, MixinB],
1357+
created() {
1358+
expectType<unknown>(this.foo)
1359+
expectType<unknown>(this.bar)
1360+
}
1361+
})
1362+
// with object props
1363+
defineComponent({
1364+
mixins: [MixinA, MixinB],
1365+
props: {
1366+
baz: {
1367+
type: Number,
1368+
required: true
1369+
}
1370+
},
1371+
created() {
1372+
expectType<unknown>(this.foo)
1373+
expectType<unknown>(this.bar)
1374+
expectType<number>(this.baz)
1375+
}
1376+
})
1377+
// with array props
1378+
defineComponent({
1379+
mixins: [MixinA, MixinB],
1380+
props: ['baz'],
1381+
created() {
1382+
expectType<unknown>(this.foo)
1383+
expectType<unknown>(this.bar)
1384+
expectType<any>(this.baz)
1385+
}
1386+
})
1387+
})
1388+
1389+
test('define mixins w/ array props', () => {
1390+
const MixinA = defineComponent({
1391+
props: ['a'],
1392+
inject: {
1393+
foo: 'foo'
1394+
},
1395+
})
1396+
const MixinB = defineComponent({
1397+
props: ['b'],
1398+
inject: ['bar'],
1399+
})
1400+
// with no props
1401+
defineComponent({
1402+
mixins: [MixinA, MixinB],
1403+
created() {
1404+
expectType<unknown>(this.foo)
1405+
expectType<unknown>(this.bar)
1406+
}
1407+
})
1408+
// with object props
1409+
defineComponent({
1410+
mixins: [MixinA, MixinB],
1411+
props: {
1412+
baz: {
1413+
type: Number,
1414+
required: true
1415+
}
1416+
},
1417+
created() {
1418+
expectType<unknown>(this.foo)
1419+
expectType<unknown>(this.bar)
1420+
expectType<number>(this.baz)
1421+
}
1422+
})
1423+
// with array props
1424+
defineComponent({
1425+
mixins: [MixinA, MixinB],
1426+
props: ['baz'],
1427+
created() {
1428+
expectType<unknown>(this.foo)
1429+
expectType<unknown>(this.bar)
1430+
expectType<any>(this.baz)
1431+
}
1432+
})
1433+
})
1434+
})

0 commit comments

Comments
 (0)