使用联合键入的条件映射使函数不可调用

时间:2018-03-22 11:39:03

标签: typescript

public class Reachability {

    class func isConnectedToNetwork() -> Bool {

        var zeroAddress = sockaddr()
        zeroAddress.sa_len = UInt8(MemoryLayout<sockaddr>.size)
        zeroAddress.sa_family = sa_family_t(AF_INET)

        guard let defaultRouteReachability = withUnsafePointer(to: &zeroAddress, {
            SCNetworkReachabilityCreateWithAddress(nil, UnsafePointer($0))
        }) else { return false }

        var flags = SCNetworkReachabilityFlags()
        guard SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags) else { return false }

        return flags.contains(.reachable) && !flags.contains(.connectionRequired)
    }

}

条件类型决定返回type Container<T> = T extends any[] ? ArrayContainer<T> : ObjectContainer<T> type ArrayContainer<T> = { set(arr: T, index: number): void } type ObjectContainer<T> = { set(obj: T): void } const testContainer = {} as any as Container<{ boxedNumber: number } | number> // Does not compile testContainer.set(33) ,无法调用ObjectContainer上的任何函数。

有没有办法强制退回ObjectContainer<{ boxedNumber: number }> | ObjectContainer<number>

使用最新的2.8版本。

3 个答案:

答案 0 :(得分:2)

正如@TitianCernicovaDragomir所指出的,您的问题是T中具有裸型参数T extends XXX ? YYY : ZZZ的条件类型最终会分布在T中的联合上。这是as designed,但它有一个de-facto standard workaroundTXXX“框”为[T] extends [XXX] ? YYY : ZZZ中的一元组。这使得条件不依赖于裸类型参数,并且它不再破坏联合。 (T最终处于协变位置的任何事情都应该有效...... {a: T} extends {a: XXX}也可以。这可能会继续有效并得到支持,因为@ahejlsberg是推荐它的人,而且他是TypeScript中的main architect of conditional types

所以在你的情况下你会做

type Container<T> = [T] extends [any[]] ? ArrayContainer<T> : ObjectContainer<T>

它会将Container<string | number>解释为ObjectContainer<string | number>,如你所愿。

但请注意,现在Container<string | number[]>被解释为ObjectContainer<string | number[]>,因为string | number[]本身不是数组。这样可以吗?它应该是ObjectContainer<string> | ArrayContainer<number[]>吗?还是ObjectContainer<string> & ArrayContainer<number[]>?或者是其他东西?不确定。

希望有所帮助;祝你好运。

答案 1 :(得分:1)

问题是条件类型将遍历union中的类型并将条件应用于union中的每个项并合并结果,因此Container<{ boxedNumber: number } | number>的结果将等同于ObjectContainer<number> | ObjectContainer<{ boxedNumber: number; }>不是ObjectContainer<number | { boxedNumber: number; }>

您可以创建一个Container<{ boxedNumber: number }>和Container的交集类型,其行为类似于您对Container<number | { boxedNumber: number }>

的期望
const testContainer = {} as any as Container<{ boxedNumber: number }> & Container<number>
testContainer.set(33)
testContainer.set({ boxedNumber: 19})

答案 2 :(得分:0)

似乎你需要额外的类型参数。

type Container<T, R> = T extends any[] ? ArrayContainer<R> : ObjectContainer<R>;

type ArrayContainer<T> = {
  set(arr: T, index: number): void
}

type ObjectContainer<T> = {
  set(obj: T): void
}

const testContainer = {} as Container<{}, number>;
testContainer.set(10);