I have a object like below
let Obj = {
['0'] : {
mode: 'x'
},
getMode: () => 'x'
}
Getting error when I create type definition like below
type Obj = {
[id: string]: {
mode: string
};
getMode: () => string
}
Getting error -- Property 'getMode' of type '() => string' is not assignable to 'string' index type '{ mode: string}'. ts(2411)
CodePudding user response:
You are using index signature, so you have to specify other type with that signature.
type Obj = {
[id: string]: { mode: string} | (() => string);
}
let Obj: Obj = {
['0']: {
mode: 'x'
},
getMode: () => 'x'
}
CodePudding user response:
This may be counterintuitive at first, but what you have is two definitions for getMode
which are mutually exclusive
Within the type Obj
you have the following:
- A generic placeholder key
[id: string]
which basically says "any key which is a string should have the following shape" (in this case{ mode: string }
) - An explicit key
getMode
whose value is of the shape() => string
As the first definition should be true for any key that is a string, it therefore clashes with the second definition. In other words, getMode
is a string key and therefore satisfies the constraint [id: string]
, meaning it must be of the shape { mode: string }
.
This concept (and potential workarounds) is explored in much more depth in similar SO answers such as this one
CodePudding user response:
In Typescript [key: string]: type
means that ALL of the object keys should be of that type. You can solve this with intersection
type Obj = {
[id: string]: {
mode: string
};
} & {
getMode: () => string
}
CodePudding user response:
When you want to use a general key with { mode: string }
type, all properties that you define which have string
key type (including getMode
) should have { mode: string }
value type. One way of detaching getMode
from general keys is to split your Obj
type in two parts:
type GetModeType = {
getMode: () => string;
};
type GeneralType<T extends string> = {
[P in T as T extends "getMode" ? never : P]: { mode: string };
};
And then create a generic type based on their intersection:
type Obj<T extends string> = GetModeType & GeneralType<T>;
Then you can create an object based on Obj
type:
const obj: Obj<"0" | "pending"> = {
getMode: () => "hello",
["0"]: { mode: "zero" },
pending: { mode: "this is pending mode." },
};
Notice that Obj
type has getMode
property with () => string
type and the other keys
that you want should be passed through as a generic type(string literals union).
You can read more about generic types and mapped types in typescript documentation.