Reputation: 570
Suppose I have a function that accepts an array of string as an argument and builds an object that has each of the array item as a key. Like this:
function buildObject(keys: string[]) {
let obj = {};
for (let i = 0; i < keys.length; i++) {
obj[keys[i]] = i;
}
return obj;
}
Is it possible to define a return type for this function so that attempt to access object key that is not defined would result in compiler error?
const obj = buildObject(['a', 'b', 'b']);
console.log(obj.a) // OK
console.log(obj.d) // I want a compiler error here
Upvotes: 0
Views: 95
Reputation: 390
I'm not very experienced with TS so I tried to figure it out and I will try to explain. I tried something like this.
My thought process is, you need to make buildObject
signature infer from your input but you need to tell TS what kind of input you have. Obviously an array of strings.
function buildObject<T extends string>(keys: T[]) {}
Then, you need to tell what's the return type (your object). Here, you need to use a mapped type so your object has keys that are type of each literal of your array of keys. I also added ?
so your initialization to {}
works.
type Obj<T extends string> = {
[key in T]?: number;
};
Full code:
type Obj<T extends string> = {
[key in T]?: number;
};
function buildObject<T extends string>(keys: T[]) {
let obj: Obj<T> = {};
for (let i = 0; i < keys.length; i++) {
obj[keys[i]] = i;
}
return obj;
}
const obj = buildObject(['a', 'b', 'b']);
console.log(obj.a); // OK
console.log(obj.d); // Compiler error
Upvotes: 0
Reputation: 5388
You can make the keys array as readonly and then use the type of its values as keys for the result object.
function buildObject<T extends string>(keys: readonly T[]): Record<T, number> {
let obj = {} as Record<T, number>;
for (let i = 0; i < keys.length; i++) {
obj[keys[i]] = i;
}
return obj;
}
const obj = buildObject(['a', 'b', 'b']);
console.log(obj.a) // OK
console.log(obj.b) // OK
console.log(obj.d) // Error
Playground link: https://tsplay.dev/wEY64w
Upvotes: 2