swiftfunctional-programming

Returning `nil` from a `compactMap()` closure fails result type check


In this snippet, I try to map [RegisteredMediaAttachment] to [BasicAttachmentInput], but only for those items that have a parseable uploadUrl.

    private func createSecondaryAttachments(
        _ attachments: [RegisteredMediaAttachment]
    ) -> [BasicAttachmentInput] {
        return attachments.compactMap {
            guard let name = URL(string: $0.registration.uploadUrl) else {
                return nil
            }

            return BasicAttachmentInput(
                name: name,
                contentType: $0.attachment.type.mime(),
                sizeBytes: $0.attachment.data.count,
                mediaId: $0.registration.media.id
            )
        }
    }

However, Swift complains on the line return nil that 'nil' is not compatible with closure result type 'BasicAttachmentInput'

This surprises me. I expect the function to compile and reduce the map result to contain only non-nil values returned from the compactMap closure. What is wrong with the snippet above?


Solution

  • Turns out Swift is just failing to infer the types correctly: simply annotating the compactMap() closure with the implied return type solves the issue:

        private func createSecondaryAttachments(
            _ attachments: [RegisteredMediaAttachment]
        ) -> [BasicAttachmentInput] {
            return attachments.compactMap { (attachment: RegisteredMediaAttachment) -> BasicAttachmentInput?
                // Note the explicit return type signature of the closure above ^
                guard let name = URL(string: $0.registration.uploadUrl) else {
                    return nil
                }
    
                return BasicAttachmentInput(
                    name: name,
                    contentType: $0.attachment.type.mime(),
                    sizeBytes: $0.attachment.data.count,
                    mediaId: $0.registration.media.id
                )
            }
        }