import * as React from "react"; import { ProtocolConfig, ProtocolLogs } from "./"; type PCConnection = Protocol extends ProtocolConfig ? Connection : never; interface Props>> { config: Config; } interface State { // Diagnostics for the component logs: ProtocolLogs; } export abstract class Protocol< Config extends ProtocolConfig> > extends React.Component, State> { // Complete any asynchronous initialization work needed by the ProtocolConfig protected async initialize() { await this.props.config.initialize(); } protected static ConfigContext: React.Context< ProtocolConfig | undefined >; protected static LogsContext: React.Context; constructor(props: Props) { super(props); this.state = { logs: new ProtocolLogs(), }; } // This trick allows us to access the static objects // defined in the derived class. See this code sample: // https://github.com/Microsoft/TypeScript/issues/5989#issuecomment-163066313 // @ts-ignore: This should always be true "constructor": typeof Protocol; public render() { const ConfigProvider = this.constructor.ConfigContext.Provider as any; const LogsProvider = this.constructor.LogsContext.Provider; const { logs } = this.state; const { config, children } = this.props; return ( {children} ); } public async componentDidMount() { const { logs } = this.state; logs.configInitializeStarted(); this.setState({ logs: logs.clone(), }); try { await this.initialize(); this.forceUpdate(); logs.configInitializeCompleted(); this.setState({ logs: logs.clone(), }); } catch (e) { logs.configInitializeFailed(e); this.setState({ logs: logs.clone(), }); } } }