空对象的条件类型

Sys*_*ank 3 typescript

是否有可能有一个条件类型可以测试可以为空的对象?

例如:

   function test<T>(a: T): T extends {} ? string : never {
        return null
      }
   let o1: {}
   let o2: { fox? }
   let o3: { fox }
   test(o1)
   test(o2)
   test(o3) // this one should be 'never'
Run Code Online (Sandbox Code Playgroud)

由于条件类型测试也适用于继承,因此所有 3 种情况都会产生“字符串”,但如果至少需要该类型的一个属性(例如非空对象类型o3) ,我想产生“从不”

更新

当我写这个问题时,我试图找出我遇到的问题的原因。我认为我应该解决我的疑问而不是我的问题,并简化我的问题。然而答案偏离了我的问题。

基本上我试图构建一个函数,其中第一个参数是一个对象,如果第一个参数可以完全部分(用 {} 初始化),则第二个参数是可选的

 function test<T extends {}>(a: T, ...x: T extends {} ? [never?] : [any])
 function test(a, b) {
   return null
 }

let o1: {}
let o2: { fox? }
let o3: { fox }

test(o1) // ok
test(o2) // ok
test(o3) // should fail and require second argument
Run Code Online (Sandbox Code Playgroud)

bug*_*ugs 6

您可以通过操作员以相对简单的方式完成此操作keyof

请记住,这never本质上相当于空集

type Foo = keyof {} // never
type Bar = keyof { a: 1, b: 2 } // "a" | "b"
Run Code Online (Sandbox Code Playgroud)

应用于您的用例,这将变为

declare function f<T>(t: T): keyof T extends never ? string : never

const a = f({}) //string
const b = f({ a: 1 }) //never
Run Code Online (Sandbox Code Playgroud)

编辑

我不确定我是否完全理解您现在包含在问题中的用例,但如果想法是像对待空对象一样仅使用可选对象来处理对象,则可以使用更多类型的机制来实现。

OptionalPropertyOf让我们借用这个问题的定义。

给定一个类型TTextends的对象object,我们可以定义以下内容

type OptionalPropertyOf<T extends object> = Exclude<{
  [K in keyof T]: T extends Record<K, T[K]>
    ? never
    : K
}[keyof T], undefined>

type ExcludeOptionalPropertyOf<T extends object> = Omit<T, OptionalPropertyOf<T>>

type Foo = { a: number, b: string }
type OptFoo = OptionalPropertyOf<Foo> // never
type NonOptFoo = ExcludeOptionalPropertyOf<Foo> // { a: number, b: string }

type Bar = { a: number, b?: string }
type OptBar = OptionalPropertyOf<Bar> // "b"
type NonOptBar = ExcludeOptionalPropertyOf<Bar> // { a: number }

type Baz = { a?: number, b?: string }
type OptBaz = OptionalPropertyOf<Baz> // "a" | "b"
type NonOptBaz = ExcludeOptionalPropertyOf<Baz> // {}
Run Code Online (Sandbox Code Playgroud)

f然后,我们稍微改变一下to的定义

declare function f<T extends object>(t: T): keyof ExcludeOptionalPropertyOf<T> extends never ? string : never
Run Code Online (Sandbox Code Playgroud)

现在你得到了你想要的东西

declare const a: Foo
declare const b: Bar
declare const c: Baz
declare const d: {}

const fa = f(a) // never
const fb = f(b) // never
const fc = f(c) // string
const fd = f(d) // string
Run Code Online (Sandbox Code Playgroud)

游乐场链接