The SDK already runs mypy in CI, but much of the public surface is still only partially annotated. I would like to improve type coverage in a way that is enforced by CI, with priority on the APIs consumers interact with directly.
The main goal is not to make a large mechanical annotation-only change. It is to tighten the type contract incrementally while preserving runtime behavior and avoiding broad escape hatches such as Any, cast, or type: ignore/attribute hacks where a real type can be expressed.
Proposed direction:
-
Start with consumer-facing modules where annotations provide the most value:
- Web API clients and responses, sync and async
- Webhook clients and responses
- public error types
- model serialization helpers used to build Slack API payloads
-
Add a small shared JSON type vocabulary for payload-like values, for example:
JSONScalar = Optional[Union[str, int, float, bool]]
JSONDict = Dict[str, JSONValue]
JSONList = List[JSONValue]
JSONValue = Union[JSONScalar, JSONDict, JSONList]
This gives model serialization and request-building code something more precise than raw dict/Any, while still matching the JSON-ish data the SDK sends and receives.
-
Tighten CI in stages rather than flipping full strict = true immediately. A practical first step could enable checks that are useful and relatively low-risk across the current package, such as:
check_untyped_defs = true
warn_return_any = true
warn_redundant_casts = true
warn_unused_configs = true
strict_equality = true
disallow_subclassing_any = true
no_implicit_reexport = true
enable_error_code = "ignore-without-code"
-
Enable disallow_untyped_defs first for selected public/consumer-facing modules. After that is green, expand the list module-by-module instead of adding a large unprincipled exclusion list.
-
Keep any remaining exclusions explicit and temporary. For example, if SCIM or legacy RTM need separate treatment, that should be called out as a known follow-up rather than hidden behind a broad ignore block.
-
Continue to use the existing project workflow:
- update canonical Web client sources, not generated files directly
- run codegen for generated Web clients
- validate with the existing mypy/lint/test scripts
Open questions for maintainers:
- Is this type-hardening direction welcome for this repository?
- Which public modules should be prioritized first?
- Are there areas, such as legacy RTM or SCIM, that maintainers would prefer to leave out of the initial pass?
- Is adding shared JSON payload aliases acceptable, or would you prefer a different naming/location for those types?
Category (place an x in each of the [ ])
The SDK already runs mypy in CI, but much of the public surface is still only partially annotated. I would like to improve type coverage in a way that is enforced by CI, with priority on the APIs consumers interact with directly.
The main goal is not to make a large mechanical annotation-only change. It is to tighten the type contract incrementally while preserving runtime behavior and avoiding broad escape hatches such as
Any,cast, ortype: ignore/attribute hacks where a real type can be expressed.Proposed direction:
Start with consumer-facing modules where annotations provide the most value:
Add a small shared JSON type vocabulary for payload-like values, for example:
JSONScalar = Optional[Union[str, int, float, bool]]JSONDict = Dict[str, JSONValue]JSONList = List[JSONValue]JSONValue = Union[JSONScalar, JSONDict, JSONList]This gives model serialization and request-building code something more precise than raw
dict/Any, while still matching the JSON-ish data the SDK sends and receives.Tighten CI in stages rather than flipping full
strict = trueimmediately. A practical first step could enable checks that are useful and relatively low-risk across the current package, such as:check_untyped_defs = truewarn_return_any = truewarn_redundant_casts = truewarn_unused_configs = truestrict_equality = truedisallow_subclassing_any = trueno_implicit_reexport = trueenable_error_code = "ignore-without-code"Enable
disallow_untyped_defsfirst for selected public/consumer-facing modules. After that is green, expand the list module-by-module instead of adding a large unprincipled exclusion list.Keep any remaining exclusions explicit and temporary. For example, if SCIM or legacy RTM need separate treatment, that should be called out as a known follow-up rather than hidden behind a broad ignore block.
Continue to use the existing project workflow:
Open questions for maintainers:
Category (place an
xin each of the[ ])