Context
I'm having trouble figuring out if I can use implied values for generic arguments in types, the same way that's possible in functions.
Assume I have the following interface defining the structure of some of my database tables:
interface Tables {
'table-users': { userId: string, username: string },
'table-posts': { postId: string, userId: string, title: string },
}
I can write an oversimplified function that allows me to write to those tables using:
const write = <T extends keyof Tables>(table: T, item: Tables[T]): boolean => {
// ... do something
return true;
}
This allows me to do
write('table-users', { userId: '123', username: 'John Doe' }); // ✅
write('table-posts', { postId: 'abc', userId: '123', title: 'First Post' }); // ✅
But not
write('table-users', { postId: 'abc' }); // ❌
write('table-posts', { userId: 'abc' }); // ❌
So far, so good.
The problem
However, now I'd like to be able to construct a type (similar to the function) that takes a property that needs to be a table name, and another property in that type needs to have the correct item format.
I figured something along these lines should work:
type Item<T extends keyof Tables> = {
table: T,
item: Tables[T],
}
and automatically allow:
const userItem: Item = {
table: 'table-users',
item: {
userId: '1',
username: 'John Doe',
}
};
const postItem: Item = {
table: 'table-posts',
item: {
postId: '123',
userId: '1',
username: 'John Doe',
}
};
or just use Item as function parameter typehint, but it does not, because it always requires explicit definition of the table name:
const userItem: Item<'table-users'> = {
table: 'table-users',
item: {
userId: '1',
username: 'John Doe',
}
};
const postItem: Item<'table-posts'> = {
table: 'table-posts',
item: {
postId: '123',
userId: '1',
title: 'First Post',
}
};
Any clue if what I'm looking for is possible in TypeScript or not? I figure it should be, because it could be and I'm probably just doing something stupid, but I can't seem to fix it.
Edit
In contrast, this is valid:
type Item = {
[T in keyof Tables]?: {
item: Tables[T]
}
}
but I'm hoping to do the same, but use T as a value, not a key.