Revision 0.34.46 (#4)

* Functions Must Support TObject as Generic Constraint

* ChangeLog

* Version
This commit is contained in:
sinclairzx81
2026-01-02 02:49:02 +09:00
committed by GitHub
parent 096e1f4a8b
commit 72d13e1bc4
6 changed files with 137 additions and 26 deletions

View File

@@ -3,6 +3,8 @@
---
### Revision Updates
- [Revision 0.34.46](https://github.com/sinclairzx81/typebox-legacy/pull/4)
- Ensure TObject Instances remain Covariant with TObject Types.
- [Revision 0.34.45](https://github.com/sinclairzx81/typebox-legacy/pull/2)
- Documentation Update - Resolve Readme Assets to TypeBox Legacy Repository.
- [Revision 0.34.44](https://github.com/sinclairzx81/typebox-legacy/pull/2)

19
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{
"name": "@sinclair/typebox",
"version": "0.34.42",
"version": "0.34.45",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@sinclair/typebox",
"version": "0.34.42",
"version": "0.34.45",
"license": "MIT",
"devDependencies": {
"@arethetypeswrong/cli": "^0.13.2",
@@ -17,7 +17,7 @@
"ajv-formats": "^2.1.1",
"mocha": "^11.1.0",
"prettier": "^2.7.1",
"typescript": "^5.9.2"
"typescript": "^5.9.3"
}
},
"node_modules/@andrewbranch/untar.js": {
@@ -1817,10 +1817,11 @@
}
},
"node_modules/typescript": {
"version": "5.9.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.2.tgz",
"integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==",
"version": "5.9.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
"dev": true,
"license": "Apache-2.0",
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
@@ -3229,9 +3230,9 @@
"dev": true
},
"typescript": {
"version": "5.9.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.2.tgz",
"integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==",
"version": "5.9.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
"dev": true
},
"undici-types": {

View File

@@ -1,6 +1,6 @@
{
"name": "@sinclair/typebox",
"version": "0.34.45",
"version": "0.34.46",
"description": "Json Schema Type Builder with Static Type Resolution for TypeScript",
"keywords": [
"typescript",
@@ -39,6 +39,6 @@
"ajv-formats": "^2.1.1",
"mocha": "^11.1.0",
"prettier": "^2.7.1",
"typescript": "^5.9.2"
"typescript": "^5.9.3"
}
}

View File

@@ -63,18 +63,39 @@ type ObjectStatic<T extends TProperties, P extends unknown[]> = ObjectStaticProp
// ------------------------------------------------------------------
export type TPropertyKey = string | number // Consider making this PropertyKey
export type TProperties = Record<TPropertyKey, TSchema>
// ----------------------------------------------------------------------------
// Required
// ----------------------------------------------------------------------------
/** Creates a RequiredArray derived from the given TProperties value. */
type TRequiredArray<
Properties extends TProperties,
RequiredProperties extends TProperties = {
[Key in keyof Properties as Properties[Key] extends TOptional<Properties[Key]> ? never : Key]: Properties[Key]
},
RequiredKeys extends string[] = UnionToTuple<Extract<keyof RequiredProperties, string>>,
Result extends string[] | undefined = RequiredKeys extends [] ? undefined : RequiredKeys,
> = Result
// ------------------------------------------------------------------
// TRequiredArray
//
// Note: Generating the RequiredArray from TProperties enables TB 1.0
// to infer TObject via the XSchema inference path. The string[] |
// undefined fallback ensures that TObject remains covariant with
// varying TObject<X> instances.
//
// ------------------------------------------------------------------
// prettier-ignore
type TIsLiteralString<Type extends string> = (
[Type] extends [string]
? [string] extends [Type]
? false
: true
: false
)
// prettier-ignore
type IsRequiredArrayLiteralConstant<RequiredTuple extends string[]> = (
RequiredTuple extends [infer Left extends string, ...infer _ extends string[]]
? TIsLiteralString<Left>
: false
)
// prettier-ignore
type TRequiredArray<Properties extends TProperties,
RequiredProperties extends TProperties = { [Key in keyof Properties as Properties[Key] extends TOptional<Properties[Key]> ? never : Key]: Properties[Key] },
RequiredUnion extends string = Extract<keyof RequiredProperties, string>,
RequiredTuple extends string[] = UnionToTuple<RequiredUnion>,
Result extends string[] | undefined = (
IsRequiredArrayLiteralConstant<RequiredTuple> extends true
? RequiredTuple
: string[] | undefined
)> = Result
/** Creates a RequiredArray derived from the given TProperties value. */
function RequiredArray<Properties extends TProperties>(properties: Properties): TRequiredArray<Properties> {
return globalThis.Object.keys(properties).filter((key) => !IsOptional(properties[key])) as never

View File

@@ -68,3 +68,29 @@ export function Expect<T extends TSchema>(schema: T) {
ToStaticEncode() {},
} as ExpectResult<T>
}
// ------------------------------------------------------------------
// IsNeverExtends
// ------------------------------------------------------------------
/** Special case for left-side `never` as given by `(never extends T ? true : false)` */
export function IsExtendsWhenLeftIsNever<Left extends unknown, Right extends unknown>(_expect: [TExtendsExpect<Left, Right>] extends [true] ? true : false) {}
// ------------------------------------------------------------------
// IsExtends
// ------------------------------------------------------------------
type TExtendsExpect<Left extends unknown, Right extends unknown> = Left extends Right ? true : false
export function IsExtends<Left extends unknown, Right extends unknown>(_expect: TExtendsExpect<Left, Right>) {}
// ------------------------------------------------------------------
// IsExtendsMutual
// ------------------------------------------------------------------
type TExtendsMutualExpect<Left extends unknown, Right extends unknown> = (<T>() => T extends Left ? 1 : 2) extends <T>() => T extends Right ? 1 : 2 ? true : false
export function IsExtendsMutual<Left extends unknown, Right extends unknown>(_expect: TExtendsMutualExpect<Left, Right>) {}
// ------------------------------------------------------------------
// IsExtendsNever
// ------------------------------------------------------------------
type TExtendsNever<Type extends unknown> = [Type] extends [never] ? true : false
export function IsExtendsNever<Type extends unknown>(_expect: TExtendsNever<Type>) {}

View File

@@ -1,6 +1,5 @@
import { Expect } from './assert'
import { Type } from '@sinclair/typebox'
import { Expect, IsExtendsMutual } from './assert'
import { Type, type TObject, type Static, type TNumber } from '@sinclair/typebox'
{
const T = Type.Object({
A: Type.String(),
@@ -68,3 +67,65 @@ import { Type } from '@sinclair/typebox'
C: number
}>()
}
// ------------------------------------------------------------------
// Required
// ------------------------------------------------------------------
{
const _A = Type.Object({})
const _B = Type.Object({ x: Type.Number() })
const _C = Type.Object({ x: Type.Number(), y: Type.Number() })
type A = (typeof _A)['required']
type B = (typeof _B)['required']
type C = (typeof _C)['required']
IsExtendsMutual<A, string[] | undefined>(true)
IsExtendsMutual<B, ['x']>(true)
IsExtendsMutual<C, ['x', 'y']>(true)
}
// ------------------------------------------------------------------
// https://github.com/sinclairzx81/typebox/issues/1500
// ------------------------------------------------------------------
{
function test<Type extends TObject>(type: Type): Static<Type> {
return null as never
}
const _A = test(Type.Object({}))
const _B = test(
Type.Object({
x: Type.Number(),
y: Type.Number(),
}),
)
const _C = test(
Type.Partial(
Type.Object({
x: Type.Number(),
y: Type.Number(),
}),
),
)
}
// ------------------------------------------------------------------
// Inference
// ------------------------------------------------------------------
{
type T = Static<typeof T>
const T = null as never as TObject<{}>
Expect(T).ToStatic<{}>()
}
{
type T = Static<typeof T>
const T = null as never as TObject
Expect(T).ToStatic<{
[x: string]: unknown
[x: number]: unknown
}>()
}
{
type T = Static<typeof T>
const T = null as never as TObject<{ x: TNumber }>
Expect(T).ToStatic<{
x: number
}>()
}