landscape/logic: type safety adjustments

This commit is contained in:
Matilde Park 2021-04-21 17:22:08 -04:00
parent 1a01e58b7b
commit 75f06a7c9e
19 changed files with 62 additions and 64 deletions

Binary file not shown.

View File

@ -88,7 +88,7 @@
"react-hot-loader": "^4.13.0",
"sass": "^1.32.5",
"sass-loader": "^8.0.2",
"typescript": "^3.9.7",
"typescript": "^4.2.4",
"webpack": "^4.46.0",
"webpack-cli": "^3.3.12",
"webpack-dev-server": "^3.11.2"

View File

@ -1,4 +1,4 @@
import { Post, GraphNode, TextContent, Graph, NodeMap } from '@urbit/api';
import { Post, GraphNode, TextContent } from '@urbit/api';
import { buntPost } from '~/logic/lib/post';
import { unixToDa } from '~/logic/lib/util';
import BigIntOrderedMap from "@urbit/api/lib/BigIntOrderedMap";
@ -7,7 +7,7 @@ import bigInt, { BigInteger } from 'big-integer';
export function newPost(
title: string,
body: string
): [BigInteger, NodeMap] {
): [BigInteger, any] {
const now = Date.now();
const nowDa = unixToDa(now);
const root: Post = {
@ -73,13 +73,16 @@ export function editPost(rev: number, noteId: BigInteger, title: string, body: s
}
export function getLatestRevision(node: GraphNode): [number, string, string, Post] {
const revs = node.children.get(bigInt(1));
const revs = node.children?.get(bigInt(1));
const empty = [1, '', '', buntPost()] as [number, string, string, Post];
if(!revs) {
return empty;
}
const [revNum, rev] = [...revs.children][0];
if(!rev) {
let revNum, rev;
if (revs?.children !== null) {
[revNum, rev] = [...revs.children][0];
}
if (!rev) {
return empty;
}
const [title, body] = rev.post.contents as TextContent[];
@ -88,18 +91,22 @@ export function getLatestRevision(node: GraphNode): [number, string, string, Pos
export function getLatestCommentRevision(node: GraphNode): [number, Post] {
const empty = [1, buntPost()] as [number, Post];
if (node.children.size <= 0) {
const childSize = node?.children?.size ?? 0;
if (childSize <= 0) {
return empty;
}
const [revNum, rev] = [...node.children][0];
if(!rev) {
let revNum, rev;
if (node?.children !== null) {
[revNum, rev] = [...node.children][0];
}
if (!rev) {
return empty;
}
return [revNum.toJSNumber(), rev.post];
}
export function getComments(node: GraphNode): GraphNode {
const comments = node.children.get(bigInt(2));
const comments = node.children?.get(bigInt(2));
if(!comments) {
return { post: buntPost(), children: new BigIntOrderedMap() };
}

View File

@ -1,4 +1,5 @@
import { TutorialProgress, Associations } from '@urbit/api';
import { Associations } from '@urbit/api';
import { TutorialProgress } from '~/types';
import { AlignX, AlignY } from '~/logic/lib/relativePosition';
import { Direction } from '~/views/components/Triangle';
@ -22,7 +23,7 @@ interface StepDetail {
alignY: AlignY | AlignY[];
offsetX: number;
offsetY: number;
arrow: Direction;
arrow?: Direction;
}
export function hasTutorialGroup(props: { associations: Associations }) {

View File

@ -15,7 +15,8 @@ function retrieve<T>(key: string, initial: T): T {
interface SetStateFunc<T> {
(t: T): T;
}
type SetState<T> = T | SetStateFunc<T>;
// See microsoft/typescript#37663 for filed bug
type SetState<T> = T extends any ? SetStateFunc<T> : never;
export function useLocalStorageState<T>(key: string, initial: T) {
const [state, _setState] = useState(() => retrieve(key, initial));

View File

@ -2,18 +2,14 @@ import React, {
useState,
ReactNode,
useCallback,
SyntheticEvent,
useMemo,
useEffect,
useRef
} from 'react';
import { Box } from '@tlon/indigo-react';
import { useOutsideClick } from './useOutsideClick';
import { ModalOverlay } from '~/views/components/ModalOverlay';
import { Portal } from '~/views/components/Portal';
import { ModalPortal } from '~/views/components/ModalPortal';
import { PropFunc } from '@urbit/api';
import { PropFunc } from '~/types';
type ModalFunc = (dismiss: () => void) => JSX.Element;
interface UseModalProps {

View File

@ -1,5 +1,5 @@
import { useRef } from 'react';
import { Primitive } from '@urbit/api';
import { Primitive } from '~/types';
export default function usePreviousValue<T extends Primitive>(value: T): T {
const prev = useRef<T | null>(null);

View File

@ -1,5 +1,4 @@
import { useState, useEffect } from "react";
import { useWaitForProps } from "./useWaitForProps";
import {unstable_batchedUpdates} from "react-dom";
export type IOInstance<I, P, O> = (
@ -10,7 +9,7 @@ export function useRunIO<I, O>(
io: (i: I) => Promise<O>,
after: (o: O) => void,
key: string
): () => Promise<void> {
): (i: I) => Promise<unknown> {
const [resolve, setResolve] = useState<() => void>(() => () => {});
const [reject, setReject] = useState<(e: any) => void>(() => () => {});
const [output, setOutput] = useState<O | null>(null);

View File

@ -5,7 +5,7 @@ export function useStatelessAsyncClickable(
onClick: (e: MouseEvent) => Promise<void>,
name: string
) {
const [state, setState] = useState<ButtonState>('waiting');
const [state, setState] = useState<AsyncClickableState>('waiting');
const handleClick = useCallback(
async (e: MouseEvent) => {
try {

View File

@ -16,7 +16,7 @@ export interface IuseStorage {
upload: (file: File, bucket: string) => Promise<string>;
uploadDefault: (file: File) => Promise<string>;
uploading: boolean;
promptUpload: () => Promise<string | undefined>;
promptUpload: () => Promise<unknown>;
}
const useStorage = ({ accept = '*' } = { accept: '*' }): IuseStorage => {

View File

@ -192,7 +192,10 @@ export function uxToHex(ux: string) {
export const hexToUx = (hex) => {
const ux = f.flow(
f.chunk(4),
f.map(x => _.dropWhile(x, y => y === 0).join('')),
// eslint-disable-next-line prefer-arrow-callback
f.map(x => _.dropWhile(x, function(y: unknown) {
return y === 0;
}).join('')),
f.join('.')
)(hex.split(''));
return `0x${ux}`;
@ -417,7 +420,7 @@ export const useHovering = (): useHoveringInterface => {
onMouseLeave,
}), [onMouseLeave, onMouseOver]);
return useMemo(() => ({ hovering, bind }), [hovering, bind]);
};

View File

@ -1,4 +1,5 @@
import { Associations, Workspace } from '@urbit/api';
import { Associations } from '@urbit/api';
import { Workspace } from '~/types';
export function getTitleFromWorkspace(
associations: Associations,

View File

@ -1,5 +1,4 @@
import _ from 'lodash';
import { StoreState } from '../../store/type';
import { StoreState } from '../store/type';
import { Cage } from '~/types/cage';
type LocalState = Pick<StoreState, 'connection'>;

View File

@ -5,16 +5,14 @@ import {
Group,
Tags,
GroupPolicy,
GroupPolicyDiff,
OpenPolicyDiff,
OpenPolicy,
InvitePolicyDiff,
InvitePolicy
} from '@urbit/api/groups';
import { Enc, PatpNoSig } from '@urbit/api';
import { Enc } from '@urbit/api';
import { resourceAsPath } from '../lib/util';
import useGroupState, { GroupState } from '../state/group';
import { compose } from 'lodash/fp';
import { reduceState } from '../state/base';
function decodeGroup(group: Enc<Group>): Group {
@ -45,11 +43,11 @@ function decodeTags(tags: Enc<Tags>): Tags {
tags,
(acc, ships, key): Tags => {
if (key.search(/\\/) === -1) {
acc.role[key] = new Set(ships);
acc.role[key] = new Set([ships]);
return acc;
} else {
const [app, tag, resource] = key.split('\\');
_.set(acc, [app, resource, tag], new Set(ships));
_.set(acc, [app, resource, tag], new Set([ships]));
return acc;
}
},
@ -125,9 +123,9 @@ const addMembers = (json: GroupUpdate, state: GroupState): GroupState => {
state.groups[resourcePath].members.add(member);
if (
'invite' in state.groups[resourcePath].policy &&
state.groups[resourcePath].policy.invite.pending.has(member)
state.groups[resourcePath].policy['invite'].pending.has(member)
) {
state.groups[resourcePath].policy.invite.pending.delete(member)
state.groups[resourcePath].policy['invite'].pending.delete(member);
}
}
}
@ -159,7 +157,7 @@ const addTag = (json: GroupUpdate, state: GroupState): GroupState => {
_.set(tags, tagAccessors, tagged);
}
return state;
}
};
const removeTag = (json: GroupUpdate, state: GroupState): GroupState => {
if ('removeTag' in json) {

View File

@ -1,18 +1,14 @@
import {
Notifications,
NotifIndex,
NotificationGraphConfig,
GroupNotificationsConfig,
UnreadStats,
Timebox
} from '@urbit/api';
import { makePatDa } from '~/logic/lib/util';
import _ from 'lodash';
import BigIntOrderedMap from "@urbit/api/lib/BigIntOrderedMap";
import BigIntOrderedMap from '@urbit/api/lib/BigIntOrderedMap';
import useHarkState, { HarkState } from '../state/hark';
import { compose } from 'lodash/fp';
import { reduceState } from '../state/base';
import bigInt, {BigInteger} from 'big-integer';
import {BigInteger} from 'big-integer';
export const HarkReducer = (json: any) => {
const data = _.get(json, 'harkUpdate', false);
@ -151,7 +147,7 @@ function graphWatchSelf(json: any, state: HarkState): HarkState {
function readAll(json: any, state: HarkState): HarkState {
const data = _.get(json, 'read-all');
if(data) {
if(data) {
clearState(state);
}
return state;
@ -264,7 +260,7 @@ function updateUnreads(state: HarkState, index: NotifIndex, f: (us: Set<string>)
if(!('graph' in index)) {
return state;
}
let unreads = _.get(state.unreads.graph, [index.graph.graph, index.graph.index, 'unreads'], new Set<string>());
let unreads: any = _.get(state.unreads.graph, [index.graph.graph, index.graph.index, 'unreads'], new Set<string>());
f(unreads);
_.set(state.unreads.graph, [index.graph.graph, index.graph.index, 'unreads'], unreads);
@ -278,7 +274,7 @@ function addNotificationToUnread(state: HarkState, index: NotifIndex, time: BigI
_.set(state.unreads.graph, path,
[
...curr.filter(c => !(c.time.eq(time) && notifIdxEqual(c.index, index))),
{ time, index}
{ time, index }
]
);
} else if ('group' in index) {
@ -287,7 +283,7 @@ function addNotificationToUnread(state: HarkState, index: NotifIndex, time: BigI
_.set(state.unreads.group, path,
[
...curr.filter(c => !(c.time.eq(time) && notifIdxEqual(c.index, index))),
{ time, index}
{ time, index }
]
);
}
@ -312,10 +308,10 @@ function removeNotificationFromUnread(state: HarkState, index: NotifIndex, time:
function updateNotificationStats(state: HarkState, index: NotifIndex, statField: 'unreads' | 'last', f: (x: number) => number) {
if('graph' in index) {
const curr = _.get(state.unreads.graph, [index.graph.graph, index.graph.index, statField], 0);
const curr: any = _.get(state.unreads.graph, [index.graph.graph, index.graph.index, statField], 0);
_.set(state.unreads.graph, [index.graph.graph, index.graph.index, statField], f(curr));
} else if('group' in index) {
const curr = _.get(state.unreads.group, [index.group.group, statField], 0);
const curr: any = _.get(state.unreads.group, [index.group.group, statField], 0);
_.set(state.unreads.group, [index.group.group, statField], f(curr));
}
}

View File

@ -18,7 +18,7 @@ export default class LaunchReducer {
]);
}
const weatherData: WeatherState = _.get(json, 'weather', false);
const weatherData: WeatherState | boolean | Record<string, never> = _.get(json, 'weather', false);
if (weatherData) {
useLaunchState.getState().set(state => {
state.weather = weatherData;

View File

@ -1,7 +1,8 @@
import _ from 'lodash';
import useSettingsState, { SettingsState } from "~/logic/state/settings";
import { SettingsUpdate } from '@urbit/api/dist/settings';
import useSettingsState, { SettingsState } from '~/logic/state/settings';
import { SettingsUpdate } from '@urbit/api/settings';
import { reduceState } from '../state/base';
import { string } from 'prop-types';
export default class SettingsReducer {
reduce(json: any) {
@ -40,21 +41,21 @@ export default class SettingsReducer {
return state;
}
putEntry(json: SettingsUpdate, state: SettingsState): SettingsState {
const data = _.get(json, 'put-entry', false);
putEntry(json: SettingsUpdate, state: any): SettingsState {
const data: Record<string, string> = _.get(json, 'put-entry', false);
if (data) {
if (!state[data["bucket-key"]]) {
state[data["bucket-key"]] = {};
if (!state[data['bucket-key']]) {
state[data['bucket-key']] = {};
}
state[data["bucket-key"]][data["entry-key"]] = data.value;
state[data['bucket-key']][data['entry-key']] = data.value;
}
return state;
}
delEntry(json: SettingsUpdate, state: SettingsState): SettingsState {
delEntry(json: SettingsUpdate, state: any): SettingsState {
const data = _.get(json, 'del-entry', false);
if (data) {
delete state[data["bucket-key"]][data["entry-key"]];
delete state[data['bucket-key']][data['entry-key']];
}
return state;
}
@ -76,7 +77,7 @@ export default class SettingsReducer {
return state;
}
getEntry(json: any, state: SettingsState) {
getEntry(json: any, state: any) {
const bucketKey = _.get(json, 'bucket-key', false);
const entryKey = _.get(json, 'entry-key', false);
const entry = _.get(json, 'entry', false);

View File

@ -9,7 +9,7 @@ export interface LaunchState extends BaseState<LaunchState> {
tiles: {
[app: string]: Tile;
},
weather: WeatherState | null,
weather: WeatherState | null | Record<string, never> | boolean,
userLocation: string | null;
baseHash: string | null;
};

View File

@ -3,10 +3,8 @@ import _ from 'lodash';
import BaseStore from './base';
import InviteReducer from '../reducers/invite-update';
import MetadataReducer from '../reducers/metadata-update';
import LocalReducer from '../reducers/local';
import { StoreState } from './type';
import { Timebox } from '@urbit/api';
import { Cage } from '~/types/cage';
import S3Reducer from '../reducers/s3-update';
import { GraphReducer } from '../reducers/graph-update';
@ -17,8 +15,6 @@ import LaunchReducer from '../reducers/launch-update';
import ConnectionReducer from '../reducers/connection';
import SettingsReducer from '../reducers/settings-update';
import GcpReducer from '../reducers/gcp-reducer';
import { OrderedMap } from '../lib/OrderedMap';
import { BigIntOrderedMap } from '../lib/BigIntOrderedMap';
import { GroupViewReducer } from '../reducers/group-view';
import { unstable_batchedUpdates } from 'react-dom';