diff --git a/.changeset/shiny-starfishes-sparkle.md b/.changeset/shiny-starfishes-sparkle.md new file mode 100644 index 00000000000..ab463b7df94 --- /dev/null +++ b/.changeset/shiny-starfishes-sparkle.md @@ -0,0 +1,5 @@ +--- +"@smithy/types": patch +--- + +custom ts3.4 downlevel for types/transform/type-transform diff --git a/packages/types/package.json b/packages/types/package.json index 977f53e928f..acb58de20ea 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -6,7 +6,7 @@ "build:cjs": "tsc -p tsconfig.cjs.json", "build:es": "tsc -p tsconfig.es.json", "build:types": "tsc -p tsconfig.types.json", - "build:types:downlevel": "downlevel-dts dist-types dist-types/ts3.4", + "build:types:downlevel": "rimraf dist-types/ts3.4 && downlevel-dts dist-types dist-types/ts3.4 && node scripts/downlevel", "stage-release": "rimraf ./.release && yarn pack && mkdir ./.release && tar zxvf ./package.tgz --directory ./.release && rm ./package.tgz", "clean": "rimraf ./dist-* && rimraf *.tsbuildinfo", "lint": "eslint -c ../../.eslintrc.js \"src/**/*.ts\"", diff --git a/packages/types/scripts/downlevel.js b/packages/types/scripts/downlevel.js new file mode 100644 index 00000000000..38ede94ec2b --- /dev/null +++ b/packages/types/scripts/downlevel.js @@ -0,0 +1,11 @@ +const fs = require("fs"); +const path = require("path"); + +const pkgRoot = path.join(__dirname, ".."); + +function replaceDownlevelFile(pathFromSrc = "") { + const code = fs.readFileSync(path.join(pkgRoot, "dist-types", "ts3.4", "downlevel-ts3.4", pathFromSrc), "utf-8"); + fs.writeFileSync(path.join(pkgRoot, "dist-types", "ts3.4", pathFromSrc), code, "utf-8"); +} + +replaceDownlevelFile("transform/type-transform.d.ts"); diff --git a/packages/types/src/downlevel-ts3.4/transform/type-transform.ts b/packages/types/src/downlevel-ts3.4/transform/type-transform.ts new file mode 100644 index 00000000000..f129361c55f --- /dev/null +++ b/packages/types/src/downlevel-ts3.4/transform/type-transform.ts @@ -0,0 +1,34 @@ +/** + * @public + * + * Transforms any members of the object T having type FromType + * to ToType. This applies only to exact type matches. + * + * This is for the case where FromType is a union and only those fields + * matching the same union should be transformed. + */ +export type Transform = RecursiveTransformExact; + +/** + * @internal + * + * Returns ToType if T matches exactly with FromType. + */ +type TransformExact = [T] extends [FromType] ? ([FromType] extends [T] ? ToType : T) : T; + +/** + * @internal + * + * Applies TransformExact to members of an object recursively. + */ +type RecursiveTransformExact = T extends Function + ? T + : T extends object + ? { + [key in keyof T]: [T[key]] extends [FromType] + ? [FromType] extends [T[key]] + ? ToType + : RecursiveTransformExact + : RecursiveTransformExact; + } + : TransformExact; diff --git a/packages/types/src/transform/type-transform.spec.ts b/packages/types/src/transform/type-transform.spec.ts index bfec30c1322..efb21356730 100644 --- a/packages/types/src/transform/type-transform.spec.ts +++ b/packages/types/src/transform/type-transform.spec.ts @@ -1,8 +1,8 @@ +import type { Transform as DownlevelTransform } from "../downlevel-ts3.4/transform/type-transform"; import type { Transform } from "./type-transform"; type Exact = [A] extends [B] ? ([B] extends [A] ? true : false) : false; -// It should transform exact unions recursively. type A = { a: string; b: number | string; @@ -10,9 +10,23 @@ type A = { nested: A; }; -type T = Transform; +{ + // It should transform exact unions recursively. -const assert1: Exact = true as const; -const assert2: Exact = true as const; + type T = Transform; -const assert3: Exact = true as const; + const assert1: Exact = true as const; + const assert2: Exact = true as const; + + const assert3: Exact = true as const; +} + +{ + // the downlevel should function similarly + type T = DownlevelTransform; + + const assert1: Exact = true as const; + const assert2: Exact = true as const; + + const assert3: Exact = true as const; +}