Sign in

Muhammad Khan

@muhammadkhan.dev
76 followers 109 following 158 posts

Despite being terribly unreasonable, I like to think of myself as rational & practical. He/Him 📍 Lahore, Pakistan

PostsRepliesMedia
Muhammad Khan @muhammadkhan.dev · 02/02/2026
github.com/muhammadk160...
export const nearestPerfectMonths = (year: number) => {
  const result = { prev: new Date(year, 0, 1), next: new Date(year + 1, 0, 1) };

  while (![4, 5].includes(result.prev.getDay())) {
    result.prev = new Date(result.prev.getFullYear() - 1, 0, 1);
  }
  while (![4, 5].includes(result.next.getDay())) {
    result.next = new Date(result.next.getFullYear() + 1, 0, 1);
  }

  return {
    prev: `${result.prev.getFullYear()}-02`,
    next: `${result.next.getFullYear()}-02`,
  };
};
020
Muhammad Khan @muhammadkhan.dev · 26/01/2026
github.com/muhammadk160...
const countVowels = (word: string) => word.match(/[aeiou]/gi)?.length || 0;

export const flippedy = (str: string) => {
  const words = str.split(" ");

  const firstWord = words[0];

  if (!firstWord) return str;

  const vowelCount = countVowels(firstWord);

  return words.reduce((acc, word) => {
    if (countVowels(word) === vowelCount) {
      return acc + " " + word.split("").reverse().join("");
    }

    return acc + " " + word;
  });
};
030
Muhammad Khan @muhammadkhan.dev · 12/01/2026
github.com/muhammadk160... I consider this a one-liner, :)
export const hungryBears = (bears: { name: string; hunger: number }[]) =>
  bears
    .filter(bear => bear.hunger > bears.reduce((sum, bear) => sum + bear.hunger, 0) / bears.length)
    .sort((a, b) => a.name.localeCompare(b.name))
    .map(bear => bear.name);
030
Muhammad Khan @muhammadkhan.dev · 08/09/2025
github.com/muhammadk160...
export const sumOfNeighbors = (arr: number[]): number => {
  let sum = 0;

  for (let i = 0; i < arr.length; i++) {
    sum += (arr[i - 1] || 0) + (arr[i] || 0) + (arr[i + 1] || 0);
  }

  return sum;
};
030
Muhammad Khan @muhammadkhan.dev · 28/07/2025
github.com/muhammadk160... Hexagons are Bestagons!
export const canFormHexagon = (sides: number[]): boolean => {
  if (sides.length !== 6) return false;

  const sideCount: Record<number, number> = {};
  for (const side of sides) {
    sideCount[side] = (sideCount[side] || 0) + 1;
  }

  return Object.values(sideCount).filter(count => count >= 2).length === 3;
};
020
Muhammad Khan @muhammadkhan.dev · 30/06/2025
github.com/muhammadk160...
export const nonRepeat = (str: string): string => {
  const charCount: Record<string, number> = {};

  for (const char of str) {
    charCount[char] = (charCount[char] || 0) + 1;
  }

  for (let i = str.length - 1; i >= 0; i--) {
    const char = str[i] || "";
    if (charCount[char] === 1) return char;
  }

  return "";
};
020
Muhammad Khan @muhammadkhan.dev · 16/06/2025
github.com/muhammadk160...
const ROMAN_MAP = {
  I: 1,
  V: 5,
  X: 10,
  L: 50,
  C: 100,
  D: 500,
  M: 1000,
} as const;

const romanToInt = (roman: string): number => {
  let total = 0;
  let prevValue = 0;

  for (let i = roman.length - 1; i >= 0; i--) {
    const currentValue = ROMAN_MAP[roman[i] as keyof typeof ROMAN_MAP];

    if (currentValue < prevValue) total -= currentValue;
    else total += currentValue;
    prevValue = currentValue;
  }

  return total;
};

export const sortMonarchs = (monarchs: string[]): string[] => {
  return monarchs.sort((a, b) => {
    const [nameA, ordinalA] = a.split(" ") as [string, string];
    const [nameB, ordinalB] = b.split(" ") as [string, string];

    const numberA = romanToInt(ordinalA);
    const numberB = romanToInt(ordinalB);

    // If years are the same, compare by name
    return nameA.localeCompare(nameB) || numberA - numberB;
  });
};
020
Muhammad Khan @muhammadkhan.dev · 10/06/2025
github.com/muhammadk160...
export type TrafficLight = "red" | "green" | "yellow";
export const isValidTrafficSequence = (sequence: TrafficLight[]): boolean => {
  let prevLight: TrafficLight | null = null;

  for (let i = 0; i < sequence.length; i++) {
    const light = sequence[i] as TrafficLight;

    if (prevLight === "red" && light !== "green") return false;
    if (prevLight === "green" && light !== "yellow") return false;
    if (prevLight === "yellow" && light !== "red") return false;

    prevLight = light;
  }

  return true;
};
010
Muhammad Khan @muhammadkhan.dev · 02/06/2025
github.com/muhammadk160... I have only one question regarding this task: "But why?"
export const nestArray = (array: any[]): any[] => {
  const result: any[] = [];
  let current = result;

  for (let i = 0; i < array.length; i++) {
    current.push(array[i]);

    if (i === array.length - 1) break;

    const nextLevel: any[] = [];
    current.push(nextLevel);
    current = nextLevel;
  }

  return result;
};
130
Muhammad Khan @muhammadkhan.dev · 30/05/2025
github.com/muhammadk160...
export const oddSum = (first: number[], second: number[]): number[][] => {
  const result: number[][] = [];

  first.forEach(x => {
    second.forEach(y => {
      if ((x + y) % 2 !== 0) {
        result.push([x, y]);
      }
    });
  });

  return result;
};
030
Muhammad Khan @muhammadkhan.dev · 20/05/2025
Baseline shamelessly "borrowed" from @tenzhiyang.com github.com/muhammadk160...
const CORNER = "+";
const VERTICAL = "|";
const HORIZONTAL = "-";
const DIAGONAL = "/";
const SPACE = " ";

const NUMBER_OF_HORIZONTAL_LINES = 3;

export const drawCube = (size: number) => {
  const horizontalLine = Array.from({ length: size * 2 + 2 })
    .map((_, i, { length }) => (i === 0 || i === length - 1 ? CORNER : HORIZONTAL))
    .join("");
  const padding = Math.floor(size / 2);
  const rows = Array.from({ length: size + NUMBER_OF_HORIZONTAL_LINES + padding });

  return (
    "\n" +
    rows
      .map((_, i, { length }) => {
        if (i === 0) {
          return SPACE.repeat(padding + 1) + horizontalLine;
        } else if (i > 0 && i < padding + 1) {
          return (
            SPACE.repeat(padding + 1 - i) +
            DIAGONAL +
            SPACE.repeat(size * 2) +
            DIAGONAL +
            SPACE.repeat(Math.max(i - 1, 0)) +
            VERTICAL
          );
        } else if (i === padding + 1) {
          return horizontalLine + SPACE.repeat(padding) + VERTICAL;
        } else if (i > padding + 1 && i < length - 1) {
          let endItem = VERTICAL;
          let paddingEnd = padding;
          if (i === size + 1) {
            endItem = CORNER;
          }
          if (i > size + 1) {
            endItem = DIAGONAL;
            paddingEnd = length - i - 2;
          }
          return VERTICAL + SPACE.repeat(size * 2) + VERTICAL + SPACE.repeat(paddingEnd) + endItem;
        } else if (i === length - 1) {
          return horizontalLine;
        } else {
          return SPACE;
        }
      })
      .join("\n") +
    "\n"
  );
};
030
Muhammad Khan @muhammadkhan.dev · 16/05/2025
github.com/muhammadk160...
export const addOperators = (origin: number, target: number): string[] => {
  const digits = origin.toString().split("");
  const result: string[] = [];

  const dfs = (index: number, path: string, currentNumber: number) => {
    if (index === digits.length) {
      if (currentNumber === target) result.push(path);
      return;
    }

    for (let i = index; i < digits.length; i++) {
      const digit = digits[i];
      const newNumber = Number(digit);

      dfs(i + 1, `${path}+${digit}`, currentNumber + newNumber);
      dfs(i + 1, `${path}-${digit}`, currentNumber - newNumber);

      // Multiply but only if BODMAS is not violated
      if (!(path.includes("+") || path.includes("-")))
        dfs(i + 1, `${path}*${digit}`, currentNumber * newNumber);
    }
  };

  // Start DFS from the first digit
  const firstDigit = digits[0] as string;
  const firstNumber = Number(firstDigit);
  dfs(1, firstDigit, firstNumber);

  return result;
};
010
Muhammad Khan @muhammadkhan.dev · 07/05/2025
"Never think that war, no matter how necessary, nor how justified, is not a crime." ~ Ernest Hemingway

I wish for calmer heads to prevail.
010
Muhammad Khan @muhammadkhan.dev · 05/05/2025
github.com/muhammadk160...
export const longestCommonPrefix = (strings: string[]): string => {
  let prefix = strings[0] || "";

  for (let i = 1; i < strings.length; i++) {
    while (strings[i]?.indexOf(prefix) !== 0) {
      prefix = prefix.slice(0, -1);
      if (prefix === "") return "";
    }
  }

  return prefix;
};
010
Muhammad Khan @muhammadkhan.dev · 28/04/2025
github.com/muhammadk160...
export const compress = (characters: string[]): string[] => {
  const compressed: string[] = [];

  let currentChar = characters[0] as string;
  let count = 1;

  for (let i = 1; i <= characters.length; i++) {
    if (characters[i] === currentChar) {
      count++;
    } else {
      compressed.push(currentChar);
      if (count > 1) {
        compressed.push(count.toString());
      }
      currentChar = characters[i] as string;
      count = 1;
    }
  }

  return compressed;
};
030
Muhammad Khan @muhammadkhan.dev · 21/04/2025
github.com/muhammadk160...
export type TIngredient = {
  name: string;
  amount: number;
};

export const calculateIngredients = (
  ingredients: TIngredient[],
  targetServings: number,
): TIngredient[] =>
  ingredients.map(ingredient => ({
    ...ingredient,
    amount: ingredient.amount * targetServings,
  }));
030
Muhammad Khan @muhammadkhan.dev · 16/04/2025
I am starting to think that noUncheckedIndexedAccess rule is overkill. github.com/muhammadk160...
const DIRECTIONS = [
  [0, 1],
  [1, 0],
  [0, -1],
  [-1, 0],
] as const;

export const largestPathSum = (grid: number[][]): number => {
  const rows = grid.length;

  if (!grid[0]) return 0;

  const cols = grid[0].length;

  let maxSum = 0;

  function dfs(x: number, y: number, visited: boolean[][], currentSum: number) {
    maxSum = Math.max(maxSum, currentSum);

    for (const [dx, dy] of DIRECTIONS) {
      const nx = x + dx;
      const ny = y + dy;

      if (!visited[nx] || !grid[nx]) continue;

      if (nx >= 0 && ny >= 0 && nx < rows && ny < cols && !visited[nx][ny]) {
        visited[nx][ny] = true;
        dfs(nx, ny, visited, currentSum + (grid[nx][ny] || 0));
        visited[nx][ny] = false;
      }
    }
  }

  for (let i = 0; i < rows; i++) {
    for (let j = 0; j < cols; j++) {
      const visited = Array.from({ length: rows }, () => Array(cols).fill(false));

      // @ts-ignore
      visited[i][j] = true;
      // @ts-ignore
      dfs(i, j, visited, grid[i][j]);
    }
  }

  return maxSum;
};
020
Muhammad Khan @muhammadkhan.dev · 07/04/2025
github.com/muhammadk160...
const getLeylandNumbers = (n: number): number[] => {
  let count = n;
  let leylandNumbers: number[] = [];

  let x = 2;

  while (count > 0) {
    for (let i = 2; i <= x; i++) {
      leylandNumbers.push(Math.pow(i, x) + Math.pow(x, i));
    }
    x++;
    count--;
  }

  return leylandNumbers.toSorted((a, b) => a - b).slice(0, n);
};
020
Muhammad Khan @muhammadkhan.dev · 01/04/2025
github.com/muhammadk160...
const getMinutes = (time: string): number => {
  const [hours, minutes] = time.split(":").map(Number);

  if (hours === undefined || minutes === undefined)
    throw new Error(`Invalid time format: ${time}`);

  return hours * 60 + minutes;
};

export const findLongestTimeGap = (times: string[]): number => {
  let longestGap = 0;

  for (let i = 0; i < times.length - 1; i++) {
    const current = times[i] as string;
    const next = times[i + 1] as string;

    longestGap = Math.max(longestGap, getMinutes(next) - getMinutes(current));
  }

  return longestGap;
};
020
Muhammad Khan @muhammadkhan.dev · 25/03/2025
github.com/muhammadk160...
export const findLongestStreak = (values: boolean[]) => {
  let max = 0;

  for (let i = 0; i < values.length; i++) {
    let current = 0;
    while (values[i]) {
      current++;
      i++;
    }

    if (current > max) {
      max = current;
    }
  }

  return max;
}
010
Muhammad Khan @muhammadkhan.dev · 11/03/2025
Thanks for forcing me to learn some basic Music Theory 😀 github.com/muhammadk160...
const SEMITONES = {
  C: 0,
  D: 2,
  E: 4,
  F: 5,
  G: 7,
  A: 9,
  B: 11,
};

export const findLargestInterval = (keys: string[]): number => {
  const intervals = keys.map(key => {
    const note = key[0] as keyof typeof SEMITONES;
    const octave = Number(key[1]);
    return SEMITONES[note] + octave * 12;
  });

  let largestInterval = 0;

  for (let i = 0; i < intervals.length - 1; i++) {
    const current = intervals[i] as number;
    const next = intervals[i + 1] as number;

    largestInterval = Math.max(largestInterval, Math.abs(current - next));
  }

  return largestInterval;
};
120
Muhammad Khan @muhammadkhan.dev · 03/03/2025
github.com/muhammadk160... Skipped last week's problem since I felt like the solution I came up with wasn't mine. 😀
export const calculatePrice = (closingDate: string, visitDate: string, price: number): number => {
  const closingDateTimestamp = new Date(closingDate).getTime();
  const visitDateTimestamp = new Date(visitDate).getTime();

  if (visitDateTimestamp > closingDateTimestamp) return price;

  const weeks = Math.floor(
    (closingDateTimestamp - visitDateTimestamp) / (1000 * 60 * 60 * 24 * 7),
  );

  for (let i = 0; i < weeks; i++) {
    price -= price * 0.1;
  }

  return price;
};
020
Muhammad Khan @muhammadkhan.dev · 17/02/2025
github.com/muhammadk160...
export const findShieldBreak = (attacks: number[], shield: number): number => {
  for (let i = 0; i < attacks.length; i++) {
    shield -= attacks[i] as number;
    if (shield < 0) return i;
  }

  return -1;
};
030
Muhammad Khan @muhammadkhan.dev · 16/02/2025
Just ran a 5k. Not gonna lie, 50% of my motivation came just from seeing all these tech people running marathons. Do I get to join the cool kids club now?
Me holding a medal for finishing a 5K run, in front of a banner saying "I am a finisher"
020
Muhammad Khan @muhammadkhan.dev · 13/02/2025
Standing strong for equality and justice at Aurat March in Lahore. 💜✊🏽 Equality should never be up for debate. #AuratMarch #EqualityForAll
My sister and I holding placards during Aurat March in Lahore.

The signs are written in Urdu. My sister is holding a sign that says: "Izzat nahi, jaan bachao", which means "Save lives not honour" I am holding a sign that says: "Ziyada soch mat bas barabar samajh", which means "Don't think too much, just think of all as equals".
020
Muhammad Khan @muhammadkhan.dev · 10/02/2025
github.com/muhammadk160...
export type TPosition = "QB" | "RB" | "WR" | "TE" | "OL" | "DL" | "LB" | "DB" | "K" | "LS";
type TRange = {
  min: number;
  max: number;
};

const ranges: Record<TPosition, TRange[]> = {
  QB: [{ min: 1, max: 19 }],
  RB: [
    { min: 1, max: 49 },
    { min: 80, max: 89 },
  ],
  WR: [
    { min: 1, max: 49 },
    { min: 80, max: 89 },
  ],
  TE: [
    { min: 1, max: 49 },
    { min: 80, max: 89 },
  ],
  OL: [{ min: 50, max: 79 }],
  DL: [
    { min: 50, max: 79 },
    { min: 90, max: 99 },
  ],
  LB: [
    { min: 1, max: 59 },
    { min: 90, max: 99 },
  ],
  DB: [{ min: 1, max: 49 }],
  K: [
    { min: 1, max: 49 },
    { min: 90, max: 99 },
  ],
  LS: [{ min: 1, max: 99 }],
};

export const availableNumbers = (position: TPosition, numbers: number[]): number[] => {
  const validRanges = ranges[position];
  let availableNumbers: number[] = [];

  for (const range of validRanges) {
    for (let i = range.min; i <= range.max; i++) {
      if (!numbers.includes(i)) {
        availableNumbers.push(i);
      }
    }
  }

  return availableNumbers;
};
030
Muhammad Khan @muhammadkhan.dev · 03/02/2025
github.com/muhammadk160...
type Operator = "+" | "-" | "*" | "/";

const isOperator = (char: string): char is Operator => {
  return char === "+" || char === "-" || char === "*" || char === "/";
};

const operate = (operand1: number, operand2: number, operator: Operator): number => {
  if (operator === "/") {
    return Math.floor(operand1 / operand2);
  } else if (operator === "*") {
    return operand1 * operand2;
  } else if (operator === "+") {
    return operand1 + operand2;
  } else {
    return operand1 - operand2;
  }
};

export const evaluatePostfix = (expression: string): number => {
  const stack: number[] = [];

  for (let i = 0; i < expression.length; i++) {
    const char = expression[i] as string;

    if (isOperator(char)) {
      const operand2 = stack.pop();
      const operand1 = stack.pop();

      if (operand1 === undefined || operand2 === undefined) {
        throw new Error("Invalid expression");
      }

      const result = operate(operand1, operand2, char);
      stack.push(result);
    } else {
      stack.push(Number(char));
    }
  }

  return stack.pop() || 0;
};
030
Muhammad Khan @muhammadkhan.dev · 27/01/2025
github.com/muhammadk160...
const getAnagrams = (s: string): string[] => {
  const anagrams: string[] = [];

  const generateAnagrams = (str: string, anagram: string) => {
    if (str.length === 0) {
      anagrams.push(anagram);
      return;
    }

    for (let i = 0; i < str.length; i++) {
      generateAnagrams(str.slice(0, i) + str.slice(i + 1), anagram + str[i]);
    }
  };

  generateAnagrams(s, "");

  return anagrams;
};

export const findAnagrams = (s: string, p: string): number[] => {
  const result: number[] = [];

  if (s.length < p.length) return result;

  const pAnagrams = getAnagrams(p);

  for (let i = 0; i < s.length - p.length + 1; i++) {
    const subStr = s.slice(i, i + p.length);
    if (pAnagrams.includes(subStr)) {
      result.push(i);
    }
  }

  return result;
};
030
Muhammad Khan @muhammadkhan.dev · 24/01/2025
A bit of old news but this screenshot shows the reason why I switched banks. This is like a textbook answer to the question, "Tell me you are storing passwords in plaintext without telling me you are using passwords in plaintext"
A screenshot of the login page from the web portal of Askari Bank Pakistan is attached.

The text reads: "Please enter 1st, 3rd, 7th and 8th characters of your password."
010
Muhammad Khan @muhammadkhan.dev · 23/01/2025
🧹 Clean up your cluttered git workspaces by removing all stale merged branches ⚠️ No warranty for important branches you forgot to name properly! If you called it fix-final-final-really-final, that one's on you.
# Remove all merged branches from local except main, prod and dev
git branch --merged | grep -Ev "(^\*|^\+|main|prod|dev)" | xargs --no-run-if-empty git branch -d

# Get rid of remote tracking branches
git remote prune origin
020
Muhammad Khan @muhammadkhan.dev · 20/01/2025
github.com/muhammadk160...
export const longestSubsequence = (sequence: number[]): number => {
  let longest = -Infinity;
  let current = 1;
  let prev = sequence[0];

  if (prev === undefined) return 0;

  for (const num of sequence.slice(1)) {
    if (Math.abs(num - prev) === 1) current++;
    else {
      longest = Math.max(longest, current);
      current = 1;
    }
    prev = num;
  }

  return Math.max(longest, current);
};
010
Muhammad Khan @muhammadkhan.dev · 13/01/2025
github.com/muhammadk160...
const NATO_ALPHABET_MAP = {
  a: "Alpha",
  b: "Bravo",
  c: "Charlie",
  d: "Delta",
  e: "Echo",
  f: "Foxtrot",
  g: "Golf",
  h: "Hotel",
  i: "India",
  j: "Juliett",
  k: "Kilo",
  l: "Lima",
  m: "Mike",
  n: "November",
  o: "Oscar",
  p: "Papa",
  q: "Quebec",
  r: "Romeo",
  s: "Sierra",
  t: "Tango",
  u: "Uniform",
  v: "Victor",
  w: "Whiskey",
  x: "X-ray",
  y: "Yankee",
  z: "Zulu",
  " ": "(space)",
  1: "One",
  2: "Two",
  3: "Three",
  4: "Four",
  5: "Five",
  6: "Six",
  7: "Seven",
  8: "Eight",
  9: "Nine",
  0: "Zero",
  ".": "Stop",
  ",": "Comma",
  "!": "Exclamation mark",
  "?": "Question mark",
  "'": "Apostrophe",
  "“": "Quote",
  "”": "Unquote",
  "-": "Hyphen",
  _: "Underscore",
  ":": "Colon",
  ";": "Semicolon",
  "(": "Bracket on",
  ")": "Bracket off",
  "/": "Slant",
  "\\": "Backslant",
} as const;

type NATO_KEY = keyof typeof NATO_ALPHABET_MAP;

export const natoify = (s: string) => {
  let result = "";
  for (const char of s) {
    const lowerChar = char.toLowerCase();

    if (lowerChar in NATO_ALPHABET_MAP) {
      result += NATO_ALPHABET_MAP[lowerChar as NATO_KEY] + " ";
    } else {
      result += char;
    }
  }

  return result.trim();
};
010
Muhammad Khan @muhammadkhan.dev · 10/01/2025
www.chess.com/awards/muham... Yay, 1500 by end of 2025 is suddenly not looking like an insurmountable task.
Stat card showing 1203 Rapid Rating on Chess.com.
020
Muhammad Khan @muhammadkhan.dev · 06/01/2025
github.com/muhammadk160...
export const permute = (s: string) => {
  if (s.length === 0) return [""];

  const result: string[] = [];

  for (let i = 0; i < s.length; i++) {
    const rest = s.slice(0, i).concat(s.slice(i + 1));
    permute(rest).forEach(restPermutation => {
      result.push(s[i] + restPermutation);
    });
  }

  return result;
};
010
Muhammad Khan @muhammadkhan.dev · 01/01/2025
Wow, great start to 2025. Hoping to reach 1500+ by end of this year
Screenshot of Unlocked Achievement on Chess.com for reaching a rating of 1100 in Rapid Chess
000
Muhammad Khan @muhammadkhan.dev · 30/12/2024
github.com/muhammadk160... Happy New Year
export const DAYS = [
  "Sunday",
  "Monday",
  "Tuesday",
  "Wednesday",
  "Thursday",
  "Friday",
  "Saturday",
] as const;
export type Day = (typeof DAYS)[number];

export const newYearsDay = (year: number) => DAYS[new Date(year, 0).getDay()] as Day;
020
Muhammad Khan @muhammadkhan.dev · 23/12/2024
github.com/MBM1607/rend... Such a lovely little pattern to this one. www.purplemath.com/modules/fact..., This article does an amazing job of explaining how this works.
export const countPerfectlyRoundCookies = (input: number): number => {
  let result = 0;
  let power = 1;

  while (5 ** power <= input) {
    result += Math.floor(input / 5 ** power);
    power++;
  }
  return result;
};
140
Muhammad Khan @muhammadkhan.dev · 22/12/2024
I've completed Day 22 of Advent of TypeScript 2024. Toughest one yet, I am already dreading, what's going to be tomorrow. adventofts.com/events/2024/22
https://tsplay.dev/N7DxDm
020
Muhammad Khan @muhammadkhan.dev · 21/12/2024
I've completed Day 21 of Advent of TypeScript 2024 So is every day going to be a variation of this now? :) adventofts.com/events/2024/21
030
Muhammad Khan @muhammadkhan.dev · 20/12/2024
I've completed Day 20th of Advent of TypeScript 2024 adventofts.com/events/2024/20
type TRes = {
	declared: string[];
	used: string[];
};

type ParseStatement<T extends string, TResult extends TRes> = T extends `${string}${
	| "let"
	| "const"
	| "var"} ${infer TId extends string} =${string}`
	? {
			declared: [...TResult["declared"], TId];
			used: TResult["used"];
		}
	: T extends `${string}(${infer TId extends string})${string}`
		? {
				used: [...TResult["used"], TId];
				declared: TResult["declared"];
			}
		: TResult;

type AnalyzeScope<
	T extends string,
	TResult extends TRes = {
		declared: [];
		used: [];
	},
> = T extends `${infer TFirst};${infer TSecond}`
	? AnalyzeScope<TSecond, ParseStatement<TFirst, TResult>>
	: ParseStatement<T, TResult>;
030
Muhammad Khan @muhammadkhan.dev · 19/12/2024
I've completed Day 19 of Advent of TypeScript 2024. adventofts.com/events/2024/19
030
Muhammad Khan @muhammadkhan.dev · 18/12/2024
Honestly, I think this is a shoe-horned use case for NoInfer. I think this would have been a simpler solution. It also yields a more specific result so it is better in my opinion.
const createStreetLight = <TColors extends string[], TColor extends TColors[number]>(colors: TColors, defaultColor: TColor) => {
  console.log(colors);
  return defaultColor;
}
000
Muhammad Khan @muhammadkhan.dev · 18/12/2024
I've completed Day 18th of Advent of TypeScript 2024. adventofts.com/events/2024/18
110
Muhammad Khan @muhammadkhan.dev · 17/12/2024
I've completed Day 17th of Advent of TypeScript 2024. adventofts.com/events/2024/17
export const upperCase = <T extends string>(x: T) => x.toUpperCase() as Uppercase<T>;
export const lowerCase = <T extends string>(x: T) => x.toLowerCase() as Lowercase<T>;
export const firstChar = <T extends string>(x: T) =>
	x[0] as T extends `${infer TFirst}${infer _}` ? TFirst : never;
export const firstItem = <T extends string[]>(x: T) => x[0] as T[0];
export const makeTuple = <T extends string>(x: T) => [x] as [T];
export const makeBox = <T>(value: T) => ({ value });

type TFunc<T1, T2> = (x: T1) => T2;

export const compose = <T1, T2, T3, T4>(f: TFunc<T1, T2>, g: TFunc<T2, T3>, h: TFunc<T3, T4>) => {
	return (x: T1) => {
		return h(g(f(x))) as T4;
	};
};
150
Muhammad Khan @muhammadkhan.dev · 16/12/2024
I've completed Day 16th of Advent of TypeScript 2024 adventofts.com/events/2024/16
type RemoveFromTuple<Tuple extends any[], SubTuple extends any[]> = Tuple extends [
	...SubTuple,
	...infer TRest,
]
	? TRest
	: never;

type TCurriedFun<TArgs extends any[], TReturn> = <TCurrentArgs extends any[]>(
	...args: TCurrentArgs
) => RemoveFromTuple<TArgs, TCurrentArgs>["length"] extends 0
	? TReturn
	: TCurriedFun<RemoveFromTuple<TArgs, TCurrentArgs>, TReturn>;

declare function DynamicParamsCurrying<TArgs extends any[], TReturn>(
	fun: (...arg: TArgs) => TReturn,
): TCurriedFun<TArgs, TReturn>;
020
Muhammad Khan @muhammadkhan.dev · 15/12/2024
I've completed Jet Fuel Pricing - Advent of TypeScript 2024 adventofts.com/events/2024/15
export type GetRoute<
	T extends string,
	TDashes extends string[] = [],
	TRoute extends [string, number][] = [],
	TWord extends string = "",
> = T extends ${infer F}${infer R}
	? F extends "-"
		? GetRoute<
				R,
				TRoute extends []
					? TWord extends ""
						? []
						: ["-"]
					: TWord extends ""
						? [F, ...TDashes]
						: ["-"],
				TWord extends "" ? TRoute : [...TRoute, [TWord, TDashes["length"]]],
				""
			>
		: GetRoute<R, TDashes, TRoute, ${TWord}${F}>
	: TWord extends ""
		? TRoute
		: [...TRoute, [TWord, TDashes["length"]]];
080
Muhammad Khan @muhammadkhan.dev · 12/12/2024
Jesus Christ knocking on a door with a handgun.

The caption reads: Open up it's Jesus
010
Muhammad Khan @muhammadkhan.dev · 11/12/2024
I just completed "Plutonian Pebbles" - Day 11 - Advent of Code 2024 This is a rare case where I feel that my solution is quite presentable. github.com/MBM1607/adve... #AdventOfCode
Code Available at: https://github.com/MBM1607/advent-of-code-2024/blob/main/src/day-11-plutonian-pebbles/plutonian-pebbles.ts
020
Muhammad Khan @muhammadkhan.dev · 10/12/2024
Same, the restriction of not being able to give the literal value was very annoying.
enum Gift {
	Coal,
	Train,
	Bicycle,
	Traditional,
	SuccessorToTheNintendoSwitch = 0b100,
	TikTokPremium = 0b1000,
	Vape = 0b10000,
	OnTheMove = 0b11010,
	OnTheCouch = 0b11100,
}
100
Muhammad Khan @muhammadkhan.dev · 09/12/2024
github.com/MBM1607/rend...
Solution for the Interview Question in the Newsletter.

View Code At: https://github.com/MBM1607/rendezvous-with-cassidoo/blob/main/src/382-wrap-gifts/wrap-gifts.ts
030