ghaiklor / type-challenges-solutions

Solutions for the collection of TypeScript type challenges with explanations
https://ghaiklor.github.io/type-challenges-solutions/
Creative Commons Attribution 4.0 International
470 stars 56 forks source link

type-challenges-solutions/en/easy-includes #23

Open utterances-bot opened 3 years ago

utterances-bot commented 3 years ago

Includes

This project is aimed at helping you better understand how the type system works, writing your own utilities, or just having fun with the challenges.

https://ghaiklor.github.io/type-challenges-solutions/en/easy-includes.html

wjx0820 commented 3 years ago

nice๐Ÿ‘๐Ÿผ

jfet97 commented 3 years ago

Sorry but the last three tests fail with this solution. I mean:

Expect<Equal<Includes<[{}], { a: 'A' }>, false>>,
Expect<Equal<Includes<[boolean, 2, 3, 5, 6, 7], false>, false>>,
Expect<Equal<Includes<[true, 2, 3, 5, 6, 7], boolean>, false>>

The extends clause is not enough.

ghaiklor commented 3 years ago

@jfet97 they've must be added those tests recently. Do you have any ideas on how we can improve the solution?

jfet97 commented 3 years ago

@ghaiklor In my solution, that is quite different, I've used the Alike util type:

import { Alike } from '@type-challenges/utils';

type Includes<T extends readonly any[], U> =
  T extends [] ?
    false :
      T extends [infer HEAD,  ...infer REST] ?
        true extends Alike<HEAD, U> ?
          true :
          Includes<REST, U> :
        never
ghaiklor commented 3 years ago

@jfet97 it's hard to tell that this solution is for "easy" level ๐Ÿ˜ฑ IMHO, by introducing those tests they've raised the level of the challenge.

jfet97 commented 3 years ago

@ghaiklor I agree with you, maybe it is now a medium difficult one.

likui628 commented 2 years ago

my solution , check each value recursively

type Includes<T extends readonly any[], U> =
  T extends [infer First, ...infer Rest]
  ? Equal<First, U> extends true
     ? true
     : Includes<Rest, U>
  : false
a-bolz commented 2 years ago

I'm wondering if there is a way to 'infer' the indexed type. Which would allow something along the lines of:

type Includes<T extends unknown[], U> = U extends T[number](infer S) ?
   S extends U ? true : false
  : false
a-bolz commented 2 years ago

which is exactly what the above commenter suggested! Should remember to still use my :eyes: when i'm exercising my :brain:

jackluson commented 2 years ago
type Includes<T extends readonly any[], U> = {} extends {
    [K in keyof T as Equal<T[K], U> extends true ? K : never]: T[K];
} ? false : true
finpluto commented 1 year ago
type Includes<T extends readonly any[], U> = {} extends {
    [K in keyof T as Equal<T[K], U> extends true ? K : never]: T[K];
} ? false : true

This solution causes following test case failed accidentally, because the length of testing tuple literal happens to be 1.

Expect<Equal<Includes<[1 | 2], 1>, false>>

A trivial Omit of length field should work fine:

type Includes<T extends readonly any[], U> = {} extends {
  [I in keyof Omit<T, "length"> as Equal<T[I], U> extends true ? I : never ]: T[I]
} ? false : true
gmoniava commented 1 year ago

@ghaiklor When you mention distributive conditional types:

E.g. if you write 2 extends 1 | 2, what TypeScript will do is actually replace it with two conditionals 2 extends 1 and 2 extends 2.

Don't the distributive types apply when left hand side of extends is union? e.g.X extends 1 ? true:false, X should be union for distribution to take place (also it must be naked generic type). In your example union is on the right hand side.

ghaiklor commented 1 year ago

@gmoniava you are right, it is a typo, thanks for noticing! I'll fix it right now.

a4da117bfb4a997a593132df53bed621a4ae3060

gmoniava commented 1 year ago

@ghaiklor yes but I think there is another problem. The left hand side of extends in the final solution, which is U, is never a union in test cases, and even if it were union then I think your solution would not work because it could return boolean instead of true or false. So I think we should not mention distributive conditionals in the solution.

ghaiklor commented 1 year ago

@gmoniava you made me to think a minute here ๐Ÿ˜„

Yeah, I remember now that we don't use distribution here at all, but instead checking if the element is in union, not vice versa. I have deleted the paragraph about distributivity here -> 6c07f782234e5e819412d2fe4bc3765a9fb6610e.