{"version":3,"file":"at.mjs","sources":["../../src/record/at.mts"],"sourcesContent":["import { Arr } from 'ts-data-forge';\nimport { type IndexOfTuple, type UnknownRecord } from 'ts-type-forge';\nimport { union } from '../compose/index.mjs';\nimport { undefinedType } from '../primitives/index.mjs';\nimport {\n  expandShapeStructure,\n  hasRecordInternals,\n  hasTupleInternals,\n  type Type,\n} from '../type.mjs';\nimport { isOptionalProperty } from './optional.mjs';\n\n/**\n * Extracts the {@link Type} stored at a single key of a record type.\n *\n * The first argument must be a record type (i.e. it must extend\n * `Type<UnknownRecord>`, like {@link pick} and {@link keyof}), and the second\n * argument is constrained to the keys declared on that record.\n *\n * The record type may be a simple record, an intersection (e.g. the result of\n * {@link mergeRecords}), a union, a recursive type, or any combination of\n * these — the underlying shape is expanded and, when a key resolves to\n * multiple member types (as in a union), the resulting types are combined with\n * {@link union}.\n *\n * @example\n * ```ts\n * import * as t from 'ts-fortress';\n *\n * const ymd = t.record({\n *   year: t.number(1900),\n *   month: t.number(1),\n *   date: t.number(1),\n * });\n *\n * const year = t.at(ymd, 'year'); // Type<number>\n *\n * year.is(2000); // true\n * ```\n */\nexport function at<\n  const R extends UnknownRecord,\n  const K extends keyof R & string,\n>(recordType: Type<R>, key: K): Type<R[K]>;\n\n/**\n * Extracts the {@link Type} stored at a single index of a tuple type.\n *\n * @example\n * ```ts\n * import * as t from 'ts-fortress';\n *\n * const tup = t.tuple([t.number(), t.string(), t.boolean()]);\n *\n * const second = t.at(tup, 1); // Type<string>\n *\n * second.is('hello'); // true\n * ```\n */\nexport function at<\n  const T extends readonly unknown[],\n  const N extends IndexOfTuple<T>,\n>(tupleType: Type<T>, index: N): Type<T[N]>;\n\nexport function at(\n  type: Type<UnknownRecord> | Type<readonly unknown[]>,\n  keyOrIndex: string | number,\n): Type<unknown> {\n  // --- Tuple index access ---\n  if (typeof keyOrIndex === 'number') {\n    if (!hasTupleInternals(type)) {\n      throw new Error(`Expected a tuple type but received: ${type.typeName}`);\n    }\n\n    const elementType = type.elementTypes[keyOrIndex];\n\n    if (elementType === undefined) {\n      throw new Error(\n        `Index ${keyOrIndex} is out of range for tuple type: ${type.typeName}`,\n      );\n    }\n\n    return elementType;\n  }\n\n  // --- Record key access ---\n  if (!hasRecordInternals(type)) {\n    throw new Error(`Expected a record type but received: ${type.typeName}`);\n  }\n\n  const shapes = expandShapeStructure(type.shapeStructure);\n\n  const memberTypes: readonly Type<unknown>[] = shapes.flatMap((shape) => {\n    const memberType = shape[keyOrIndex];\n\n    return memberType === undefined ? [] : [memberType];\n  });\n\n  // If the key is optional in any member, the accessed value may be undefined,\n  // matching the `T | undefined` produced by `R[K]` for optional keys.\n  const hasOptionalMember = memberTypes.some(isOptionalProperty);\n\n  const collected: readonly Type<unknown>[] = hasOptionalMember\n    ? Arr.toPushed(memberTypes, undefinedType)\n    : memberTypes;\n\n  if (Arr.isMinLengthTuple(collected, 2)) {\n    return union(collected, {\n      typeName: `${type.typeName}[${JSON.stringify(keyOrIndex)}]`,\n    });\n  }\n\n  if (Arr.isNonEmpty(collected)) {\n    return collected[0];\n  }\n\n  throw new Error(\n    `Key ${JSON.stringify(keyOrIndex)} does not exist on record type: ${type.typeName}`,\n  );\n}\n"],"names":[],"mappings":";;;;;;;;AAgEO,SAAS,EAAA,CACd,MACA,UAAA,EACe;AAEf,EAAA,IAAI,OAAO,eAAe,QAAA,EAAU;AAClC,IAAA,IAAI,CAAC,iBAAA,CAAkB,IAAI,CAAA,EAAG;AAC5B,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,oCAAA,EAAuC,IAAA,CAAK,QAAQ,CAAA,CAAE,CAAA;AAAA,IACxE;AAEA,IAAA,MAAM,WAAA,GAAc,IAAA,CAAK,YAAA,CAAa,UAAU,CAAA;AAEhD,IAAA,IAAI,gBAAgB,MAAA,EAAW;AAC7B,MAAA,MAAM,IAAI,KAAA;AAAA,QACR,CAAA,MAAA,EAAS,UAAU,CAAA,iCAAA,EAAoC,IAAA,CAAK,QAAQ,CAAA;AAAA,OACtE;AAAA,IACF;AAEA,IAAA,OAAO,WAAA;AAAA,EACT;AAGA,EAAA,IAAI,CAAC,kBAAA,CAAmB,IAAI,CAAA,EAAG;AAC7B,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,qCAAA,EAAwC,IAAA,CAAK,QAAQ,CAAA,CAAE,CAAA;AAAA,EACzE;AAEA,EAAA,MAAM,MAAA,GAAS,oBAAA,CAAqB,IAAA,CAAK,cAAc,CAAA;AAEvD,EAAA,MAAM,WAAA,GAAwC,MAAA,CAAO,OAAA,CAAQ,CAAC,KAAA,KAAU;AACtE,IAAA,MAAM,UAAA,GAAa,MAAM,UAAU,CAAA;AAEnC,IAAA,OAAO,UAAA,KAAe,MAAA,GAAY,EAAC,GAAI,CAAC,UAAU,CAAA;AAAA,EACpD,CAAC,CAAA;AAID,EAAA,MAAM,iBAAA,GAAoB,WAAA,CAAY,IAAA,CAAK,kBAAkB,CAAA;AAE7D,EAAA,MAAM,YAAsC,iBAAA,GACxC,GAAA,CAAI,QAAA,CAAS,WAAA,EAAa,aAAa,CAAA,GACvC,WAAA;AAEJ,EAAA,IAAI,GAAA,CAAI,gBAAA,CAAiB,SAAA,EAAW,CAAC,CAAA,EAAG;AACtC,IAAA,OAAO,MAAM,SAAA,EAAW;AAAA,MACtB,QAAA,EAAU,GAAG,IAAA,CAAK,QAAQ,IAAI,IAAA,CAAK,SAAA,CAAU,UAAU,CAAC,CAAA,CAAA;AAAA,KACzD,CAAA;AAAA,EACH;AAEA,EAAA,IAAI,GAAA,CAAI,UAAA,CAAW,SAAS,CAAA,EAAG;AAC7B,IAAA,OAAO,UAAU,CAAC,CAAA;AAAA,EACpB;AAEA,EAAA,MAAM,IAAI,KAAA;AAAA,IACR,OAAO,IAAA,CAAK,SAAA,CAAU,UAAU,CAAC,CAAA,gCAAA,EAAmC,KAAK,QAAQ,CAAA;AAAA,GACnF;AACF;;;;"}