         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.
      

            $0.filter(isIncluded)
        }
    }
}

public extension Thenable where T: Collection {

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

    #if swift(>=4)
    /**
     `Promise<[T]>` => `KeyPath<T, U>` => `Promise<[U]>`

         firstly {
             .value([Person(name: "Max"), Person(name: "Roman"), Person(name: "John")])
         }.mapValues(\.name).done {
             // $0 => ["Max", "Roman", "John"]
         }
     */
    func mapValues<U>(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ keyPath: KeyPath<T.Iterator.Element, U>) -> Promise<[U]> {
        return map(on: on, flags: flags){ $0.map { $0[keyPath: keyPath] } }
    }
    #endif

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

