简体   繁体   中英

TypeScript, object with prop of type bool or () => bool, How to handle?

I have a Vue app. I'm converting vanilla JS to TypeScript and I have this pattern; I have a component that accepts a property item which is an object with several properties following the scheme:

type Button = {
    variant?: 'string' | function(): string;
    ...others...
}

Everything works by the idea that it accepts a string or a function that returns a string (it also works for booleans etc...)

In the same component, I have a function that checks if the key is a function and if it is executing it, and returns the result if it is not a function simply passes on whatever it is.

private finalize<K extends keyof Button>(item: Button, key: K, target: Button["target"]): Button[K] {
  let finalized:Button[K]? = null;
  if (identify(item).isObject()) {
    if (identify(item[key]).isFunction()) {
      finalized = item[key](target);
    } else {
      finalized = item[key];
    }
  } else if (item) {
    finalized = item;
  };
  return finalized;
}

My problem is that i want to narrow the returned type from a union like - string | () => string string | () => string - to string . Instead my finalize function return type is still string | () => string string | () => string . How do I mke TS understand that if it is a function it will execute it

A good solution that'd work for any return type:

function isCallable<T>(value: T | (() => T)): value is (() => T) {
  return value instanceof Function;
}

And then you'd use this way:

let myValue: string | () => string;

// Here, myValue should be assigned somethign, otherwise TypeScript will
// complain that it's used before it gets anything assigned. Let's give it
// something and manually type it as `any` so TypeScript is still in the dark
// regarding its true type.
myValue = "hello" as any;

if (isCallable(myValue)) {
  // myValue is narrowed as a function that returns a string
} else {
  // myValue is narrowed as a string
}

This will work with any type, thanks to the genericness of the isCallable function. It accepts anything that either a type ( T ) or a function that returns the T type. Once you call it, and thanks to the is keyword in its signature, TypeScript can narrow down the given variable's type.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM