这是indexloc提供的服务,不要输入任何密码
Skip to content

9155 - ValidDate (🎥 Video Explanation and Solution) #25355

@dimitropoulos

Description

@dimitropoulos

9155 - ValidDate

I found this challenge to be quite fun. It's a problem that has a few vastly different ways to approach it, which ends up being a good lesson on how to balance keeping things terse and making it easy to read. It's fun to see what TypeScript can do! Even parsing dates.. hah.

🎥 Video Explanation

Release Date: 2023-05-02 19:00 UTC

ValidDate

🔢 Code

// ============= Test Cases =============
import type { Equal, Expect } from './test-utils'

type A1 = ValidDate<'0102'>;
type B1 = true;
type C1 = Expect<Equal<A1, B1>>;

type A2 = ValidDate<'0131'>;
type B2 = true;
type C2 = Expect<Equal<A2, B2>>;

type A3 = ValidDate<'1231'>;
type B3 = true;
type C3 = Expect<Equal<A3, B3>>;

type A4 = ValidDate<'0229'>;
type B4 = false;
type C4 = Expect<Equal<A4, B4>>;

type A5 = ValidDate<'0100'>;
type B5 = false;
type C5 = Expect<Equal<A5, B5>>;

type A6 = ValidDate<'0132'>;
type B6 = false;
type C6 = Expect<Equal<A6, B6>>;

type A7 = ValidDate<'1301'>;
type B7 = false;
type C7 = Expect<Equal<A7, B7>>;

type A8 = ValidDate<'0123'>;
type B8 = true;
type C8 = Expect<Equal<A8, B8>>;

type A9 = ValidDate<'01234'>;
type B9 = false;
type C9 = Expect<Equal<A9, B9>>;

type A10 = ValidDate<''>;
type B10 = false;
type C10 = Expect<Equal<A10, B10>>;

// ============= Your Code Here =============
type Day = {
  '01': '31';
  '02': '28';
  '03': '31';
  '04': '30';
  '05': '31';
  '06': '30';
  '07': '31';
  '08': '31';
  '09': '30';
  '10': '31';
  '11': '30';
  '12': '31';
};
type Month = keyof Day;

type RemoveZero<T> =
  T extends `0${infer R}`
  ? RemoveZero<R>
  : T;

type CheckDay<
  Day extends string,
  DaysThisMonth extends string,
  DayWithoutZero extends string = RemoveZero<Day>,
  Count extends 1[] = []
> =
  DayWithoutZero extends ''
  ? false
  : `${Count['length']}` extends DayWithoutZero
    ? true
    : `${Count['length']}` extends DaysThisMonth
      ? false
      : CheckDay<
          Day,
          DaysThisMonth,
          DayWithoutZero,
          [...Count, 1]
        >;

type ValidDate<T extends string> =
  T extends `${infer M1}${infer M2}${infer Tail}`
  ? `${M1}${M2}` extends Month
    ? CheckDay<Tail, Day[`${M1}${M2}`]>
    : false
  : false;

// ============== Alternatives ==============
// @teamchong
type _1_9 = 1|2|3|4|5|6|7|8|9;
type _0_9 = 0|1|2|3|4|5|6|7|8|9;
type _0_8 = 0|1|2|3|4|5|6|7|8;
type D30 = `0${_1_9}`|`1${_0_9}`|`2${_0_9}`|`30`;
type D31 = `0${_1_9}`|`1${_0_9}`|`2${_0_9}`|`30`|`31`;
type D28 = `0${_1_9}`|`1${_0_9}`|`2${_0_8}`;
type M31 = `${`01`|`03`|`05`|`07`|`08`|`10`|`12`}${D31}`;
type M30 = `${`04`|`06`|`09`|`11`}${D30}`;
type M28 = `02${D28}`;
type ValidDate<T> =
  T extends M28 | M30 | M31
  ? true
  : false;

// @LoTwT
type Num = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9;
type MM = `0${Num}` | `1${0 | 1 | 2}`;
type AllDate =
    // All months have 0-9 days
  | `${MM}${`${0}${Num}`

    // All months have 10-19 days
  | `${1}${0 | Num}`

    // February
  | `2${0 | Exclude<Num, 9>}`}`
  
    // Non-February months ending with 30 days
    | `${Exclude<MM, '02'>}${29 | 30}`
    
    // Add the 31th days for those months that have it
  | `${Exclude<MM, '02' | '04' | '06' | '09' | '11'>}${31}`;

type ValidDate<T> =
  T extends AllDate
  ? true
  : false;

// @jiangshanmeta
type _1_9 = '1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9';
type _0_9 = '0'|_1_9;
type Thirty =
  | `0${_1_9}`
  | `1${_0_9}`
  | `2${_0_9}`
  | '30';
type ThirtyOne = Thirty | '31';
type TwentyEight = Exclude<Thirty,'30' | '29'>;
type DateMap = {
  '01':ThirtyOne;
  '02':TwentyEight;
  '03':ThirtyOne;
  '04':Thirty;
  '05':ThirtyOne;
  '06':Thirty;
  '07':ThirtyOne;
  '08':ThirtyOne;
  '09':Thirty;
  '10':ThirtyOne;
  '11':Thirty;
  '12':ThirtyOne;
};
type ValidDate<T extends string> =
  T extends `${infer F}${infer S}${infer Tail}`
  ? `${F}${S}` extends keyof DateMap
    ? Tail extends DateMap[`${F}${S}`]
      ? true
      : false
    : false
  : false;

➕ More Solutions

For more video solutions to other challenges: see the umbrella list! #21338

Metadata

Metadata

Assignees

No one assigned

    Labels

    9155answerShare answers/solutions to a questionenin English

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions