         }
     }
 
+    #if swift(>=4)
+    /**
+     `Promise<[T]>` => `KeyPath<T, U?>` => `Promise<[U]>`
+
+         firstly {
+             .value([Person(name: "Max"), Person(name: "Roman", age: 26), Person(name: "John", age: 23)])
+         }.compactMapValues(\.age).done {
+             // $0 => [26, 23]
+         }
+     */
+    func compactMapValues<U>(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ keyPath: KeyPath<T.Iterator.Element, U?>) -> Promise<[U]> {
+        return map(on: on, flags: flags) { foo -> [U] in
+          #if !swift(>=4.1)
+            return foo.flatMap { $0[keyPath: keyPath] }
+          #else
+            return foo.compactMap { $0[keyPath: keyPath] }
+          #endif
+        }
+    }
+    #endif
+
     /**
      `Promise<[T]>` => `T` -> `Promise<U>` => `Promise<[U]>`
 

        return map(on: on, flags: flags){ try $0.map(transform) }
    }

    /**
     `Promise<[T]>` => `T` -> `[U]` => `Promise<[U]>`


        return rp
    }

    #if swift(>=4)
    /**
    Similar to func `compactMap<U>(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ transform: @escaping(T) throws -> U?) -> Promise<U>`, but accepts a key path instead of a closure.
    
    - Parameter on: The queue to which the provided key path for value dispatches.
    - Parameter keyPath: The key path to the value that is using when this Promise is fulfilled. If the value for `keyPath` is `nil` the resulting promise is rejected with `PMKError.compactMap`.
    - Returns: A new promise that is fulfilled with the value for the provided key path.
    */
    func compactMap<U>(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ keyPath: KeyPath<T, U?>) -> Promise<U> {
        let rp = Promise<U>(.pending)
        pipe {
            switch $0 {
            case .fulfilled(let value):
                on.async(flags: flags) {
                    do {
                        if let rv = value[keyPath: keyPath] {
                            rp.box.seal(.fulfilled(rv))
                        } else {
                            throw PMKError.compactMap(value, U.self)
                        }
                    } catch {
                        rp.box.seal(.rejected(error))
                    }
                }
            case .rejected(let error):
                rp.box.seal(.rejected(error))
            }
        }
        return rp
    }
    #endif

    /**
     The provided closure is executed when this promise is fulfilled.
     
