Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

697 - Tag #11465

Open
teamchong opened this issue Jun 11, 2022 · 0 comments
Open

697 - Tag #11465

teamchong opened this issue Jun 11, 2022 · 0 comments
Labels
697 answer Share answers/solutions to a question en in English

Comments

@teamchong
Copy link

teamchong commented Jun 11, 2022

interface Tagged {
  [UNIQUE_SYMBOL]: () => string
}

type Is<A, B> = (<G>() => G extends A ? 1 : 0) extends (<G>() => G extends B ? 1 : 0) ? true : false

type Tagging<This, Tag extends string = string, NewTag extends Tagged = {[UNIQUE_SYMBOL]: (this: This) => Tag}> = true extends Is<This & NewTag, This> ? NewTag : ReturnType<<T extends This & NewTag>() => {[K in keyof T]: T[K]}>

type ExtractTagged<B>
  = true extends Is<B, any> | Is<Extract<B, Tagged>, never> ? Tagging<B, ''>
  : ExtractOne<Extract<B, Tagged>> extends infer S extends Tagged
    ? S extends Tagging<infer This>
      ? true extends Is<Exclude<B, S | This>, never> ? S : S | ExtractTagged<Exclude<B, S | This>>
    : never /* infer X */
  : never /* infer S */

type ExtractTags<B, I extends Tagged = ExtractTagged<B>, Tags = true extends Is<B, any> | Is<I, never> ? '' : I extends I ? ReturnType<I[US]> : never /* This extends I */>
  = true extends Is<Tags, ExtractOne<Tags>> ? Tags : ''

type ExtractOne<U> = (U extends U ? (_: () => U) => void : never) extends (_: infer I extends () => U) => void ? ReturnType<I> : never

type Split<Tags extends string> = Tags extends '' ? [] : Tags extends `${infer Tag} ${infer Rest}` ? Tag extends '' ? Split<Rest> : [Tag, ...Split<Rest>] : [Tags]

type Join<Tags extends readonly string[]> = Tags extends [infer S extends string, ...infer R extends string[]] ? R extends [] ? S : `${S extends '' ? '' : `${S} `}${Join<R>}` : ''

type Append<Tags extends string, T extends string> = string extends Tags ? T : Tags extends '' ? T : ` ${Tags} ` extends ` ${T} ` ? Tags : `${Tags} ${T}`

type GetTags<B, Tags extends string = ExtractTags<B>> = true extends Is<Tags, never> ? [] : Split<Tags>

type Tag<B, T extends string, I extends Tagged = ExtractTagged<B>>
  = true extends Is<I, never> ? B
  : I extends Tagging<infer This, infer Tags extends string>
    ? Tagging<This, Append<Tags, T>> extends infer NewTagged
      ? true extends Is<This | NewTagged, This> ? NewTagged : This | NewTagged
    : never /* infer NewI */
  : never /* infer This, infer Tags */

type UnTag<B, I extends Tagged = ExtractTagged<B>>
  = true extends Is<I, never> ? B
  : I extends I ? I extends Tagging<infer This> ? This : never /* infer This */ : never /* I extends I */

type HasTag<B, T extends string, Tags extends string = ExtractTags<B>> = ` ${Tags} ` extends `${any} ${T} ${any}` ? true : false
type HasTags<B, T extends readonly string[], Tags extends string = ExtractTags<B>> = ` ${Tags} ` extends `${any} ${Join<T>} ${any}` ? true : false
type HasExactTags<B, T extends readonly string[], Tags extends string = ExtractTags<B>> = Tags extends Join<T> ? true : false

Playground

@teamchong teamchong added answer Share answers/solutions to a question en in English labels Jun 11, 2022
@github-actions github-actions bot added the 697 label Jun 11, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
697 answer Share answers/solutions to a question en in English
Projects
None yet
Development

No branches or pull requests

1 participant