Когда использовать typealias?

Пока я понимаю, что typealias — это именованный псевдоним существующего типа. Используя typealias, я мог бы сделать что-то вроде:

typealias MyString = String
var str: MyString?

typealias Strings = [String]
var strs: Strings?

что приводит к объявлению переменной str как строки и strs как массива строк.

Даже для пользовательского типа:

class MyClass {}
typealias MyClsType = MyClass
var myClass: MyClsType

Однако это кажется немного бесполезным; Логически, какова цель объявления -например- var str: MyString? строкой вместо var str: String?? даже больше, var str: String более выразительно.


person Ahmad F    schedule 21.11.2017    source источник
comment
Вот один практический пример: stackoverflow.com/a/43302448/3141234   -  person Alexander    schedule 22.11.2017


Ответы (2)


На самом деле, нет никаких сомнений в том, что создание псевдонима типа для, скажем, String: typealias MyString = String было бы не так уж полезно (я также предположил бы, что объявление псевдонима типа для Dictionary с определенным типом ключа/значения: typealias CustomDict = Dictionary<String, Int> может оказаться не таким уж полезным для ты.

Однако когда дело доходит до работы с составными типами вы определенно заметите преимущества псевдонимов типов.

Пример:

Учтите, что вы реализуете менеджер, который многократно работает с замыканиями со многими параметрами в своих функциях:

class MyManager {
    //...

    func foo(success: (_ data: Data, _ message: String, _ status: Int, _ isEnabled: Bool) -> (), failure: (_ error: Error, _ message: String, _ workaround: AnyObject) -> ()) {
        if isSuccess {
            success(..., ..., ..., ...)
        } else {
            failure(..., ..., ...)
        }
    }

    func bar(success: (_ data: Data, _ message: String, _ status: Int, _ isEnabled: Bool) -> (), failure: (_ error: Error, _ message: String, _ workaround: AnyObject) -> ()) {
        if isSuccess {
            success(..., ..., ..., ...)
        } else {
            failure(..., ..., ...)
        }
    }

    // ...
}

Как видите, сигнатуры методов выглядят действительно утомительно! оба метода принимают success и failure параметров, каждый из них является замыканием с аргументами; Кроме того, для реализации подобных функций не так уж и логично сохранять параметры копипаст.

Реализация typealias для такого случая была бы уместна:

class MyManager {
    //...

    typealias Success = (_ data: Data, _ message: String, _ status: Int, _ isEnabled: Bool) -> ()
    typealias Failure = (_ error: Error, _ message: String, _ workaround: AnyObject) -> ()

    func foo(success: Success, failure: Failure) {
        if isSuccess {
            success(..., ..., ..., ...)
        } else {
            failure(..., ..., ...)
        }
    }

    func bar(success: Success, failure: Failure) {
        if isSuccess {
            success(..., ..., ..., ...)
        } else {
            failure(..., ..., ...)
        }
    }

    // ...
}

Таким образом, он будет более выразительным и читабельным.


Кроме того, вы можете проверить средний рассказ Я писал об этом.

person Ahmad F    schedule 21.11.2017
comment
typealias вместо String может быть полезным: - предоставляет семантическое значение читателю: let result: Token, а не let result: String было бы немного более значимым. - если вы каждый раз решите перейти от примитивного значения к пользовательскому типу, вам поможет псевдоним типа. Например. если Token станет struct, то компилятор сообщит вам места использования. Первая компиляция после изменения typealias на struct будет компилироваться как есть! - person raheel; 07.11.2018
comment
Я сейчас перед той же дилеммой. Есть куча длинных универсальных типов, таких как от Results<ObjcA> до Results<ObjcE> (используя ObjcX в качестве примера), и несколько словарей с похожими формами: [ObjA:[ObjB]] где использование таких имен, как ObjAQueryResult или ObjAObjBMapping, имеет больше смысла, так как для ввода требуется меньше кода. НО, я чувствую, что когда другой разработчик вступит во владение, будет дополнительная когнитивная нагрузка, пусть и небольшая, при поиске того, что представляет собой каждый из этих псевдонимов, по крайней мере, до тех пор, пока они не привыкнут к этой конкретной части кода, которая уже сложна. тем не мение. - person cumanzor; 04.06.2019

Обычный способ использования typealias для меня — это работа с замыканиями:

typealias VoidClosure = () -> Void

func updateFrom(completion: @escaping VoidClosure) { }

person Serg Tsarikovskiy    schedule 22.11.2017
comment
Не только для замыканий, упоминание составных типов было бы более точным. Вы можете проверить ссылку составных типов в моем ответе, чтобы узнать, что это значит (Типы). - person Ahmad F; 22.11.2017
comment
@AhmadF да. Я полностью согласен с тобой. Это облегчает чтение кода, когда появляются некоторые сложные аргументы типов. - person Serg Tsarikovskiy; 22.11.2017