1

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 } => {
1
  • 1
    The syntax is {[k in K]: string} for a mapped type, or you can write Record<K, string> for convenience. Commented Mar 30, 2022 at 12:07

1 Answer 1

3

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>.

TypeScript playground

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.