0

I want to use an interface with generic union types like this:

interface IOperator {
  <U>(a: U[], b: U[] | U): boolean
}

export const intersects: IOperator = (a, b) => a.some((el) => b.includes(el))
export const includes: IOperator = (a, b) => a.includes(b)

However, TS gives me error on both regarding one of the union types:

Property 'includes' does not exist on type 'U | U[]'.
  Property 'includes' does not exist on type 'U'.

How do I typecast properly here?

I tried:

export const intersects: IOperator = (a, b) => a.some((el) => (b as U[]).includes(el))

However, that gives me an error:

Cannot find name 'U'.

So how to handle generic union types?

I know that for the intersects method the types for input b should only be arrays and for the includes method the types for input b should never be arrays. The idea for the interface is to not repeat myself as I have plenty of methods where some require b to be an array and others to not be an array. I'd try to avoid to create two separate interfaces.

Thank you!

2
  • 2
    That TS error is correct; if b is U not an array of U, it (probably) won't have an includes method. Commented Jan 4, 2021 at 15:46
  • 2
    Instead of typecasting you need to check if b is an array. Commented Jan 4, 2021 at 15:47

2 Answers 2

1

I think:

export const intersects: IOperator = (a, b) => a.some((el) => Array.isArray(b)&&b.includes(el))

should work. Otherwise, b might not be an Array of type U, so that includes is not available.

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

Comments

1

The issue with using casting here is if the value of B doesn't match your casting, you'll have a runtime error. That being said, your use case may be valid and we just don't have the context available to see it. Otherwise, you may want to do a runtime check as suggested by some of the comments to your post.

This solution uses function to give you access to U, and then assigns the function to a const so you can type check that your function signature matches your interface.

interface IOperator {
  <U>(a: U[], b: U[] | U): boolean
}

function _intersects <U>(a: U[], b: U[] | U): boolean {
  return a.some((el) => (b as U[]).includes(el));
}
export const intersects: IOperator = _intersects;

function _includes <U>(a: U[], b: U[] | U): boolean {
  return a.includes(b as U);
}
export const includes: IOperator = _includes;

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.