Here is the function I'd like to write, and I cannot quite get the generic to work.
As you can see - I'd like to return that T[K] is definitely a string - the point is to be able to use it
a = {key: "unknown type"};
if (!validateRequiredStringKey(a, "key")) {
return
}
// Here we should know that a.key is a string
funcThatTakesAString(a.key);
export const validateRequiredStringKey = <
T,
K extends keyof T & (string | number)
>(
obj: T,
key: K
): obj is T & { [K]: string } => {
const v = obj[key];
if (!(typeof v === "string")) {
throw new ValidationError(`${key} is not a string`);
}
if (v === "") {
throw new ValidationError(`${key} is empty`);
}
return true;
};
The errors from tsc
are
src/domain/validations/utils.ts:12:17 - error TS1170: A computed property name in a type literal must refer to an expression whose type is a literal type or a 'unique symbol' type.
12 ): obj is T & { [K]: string } => {
~~~
src/domain/validations/utils.ts:12:18 - error TS2693: 'K' only refers to a type, but is being used as a value here.
12 ): obj is T & { [K]: string } => {
CodePudding user response:
I haven't thoroughly checked the definition of validateRequiredStringKey
, but you can make it work by replacing { [K]: string }
with {[Key in K]: string}
, or just Record<K, string>
.