Zeka 的记事本

2021 年 6 月
更新 Mastodon
2021612 日说: Linux

由于没有自己构建而是直接拉取的官方镜像,所以不需要在本地 build。

在确定要升级前,最好仔细阅读官方的 release notes这里。如果没有 breaking changes,则可以按照一般流程走下去。

备份数据库:

docker exec mastodon_db_1 pg_dump -Fc -U postgres postgres > name_of_the_backup.dump

如果没有使用 OSS 等外部存储,媒体文件也是需要进行备份的,但是一般不会有问题。

拉取最新镜像:

docker pull tootsuite/mastodon:latest

按照 官方指示 进行操作。一般来说操作的时候是不需要停止镜像的。

操作完成后,重启镜像:

docker-compose down
docker-compose up -d

启动后可以通过 docker ps 查看是否有异常。Mastodon 启动需要一定时间。

在确保稳定后,删除旧镜像。Mastodon 镜像文件比较大,虽然大部分 layer 可以直接复用,但是还是会对存储空间产生一定压力。重新 pull 最近镜像后,旧镜像变为 untagged

下面指令不仅仅去除 untagged 镜像,还会移除没有使用的任何镜像,网络等等。如果你有要保留那些镜像的需求,这条指令不适合你。

sudo docker system prune -a
Typescript 简记
202161 日说: 前端

之前总是在写,而没有参照文档。最近抽空简单看了看文档,大概梳理了一下。

例子是自己写的,稍微结合了下自己的使用场景,希望能有帮助。

反正还是会忘,就算记下来了也不会翻。

接口声明

interface Item {
	my: string
}

interface SimpleDict {
    [dicStr: string]: Item
}

interface IWithFunc {
	foo(item: Item): void
}

声明类型并解构

interface IProps {
    fuck: string
   	girlFriend: false
}

// for simple function
const demoFunc = ({ girlFriend }: IProps) => {
    console.log(`You have ${girlFriend ? 'a' : 'no'} girlfriend.`);
};

// React.FC is discouraged, but for me, I like it.
// See: https://react-typescript-cheatsheet.netlify.app/docs/basic/getting-started/function_components
export const ReactFC: FC<IProps> = ({ girlFriend }) => {
    return (<>{ girlFriend }</>);
};

由于基本只作为用户,而不作为包提供者,所以是使用泛型多于自己定义。

为 document.get* 加上类型

虽然奇怪 document.getElementById 这类 API 居然没有泛型,但是既然人家这样设计的,就只能遵守。

const ele = document.getElementById('canvas') as HTMLCanvasElement;

下面的写法是不存在的:

const ele = document.getElementById<HTMLCanvasElement>('some-id');

但是有下面的等价写法(angle-bracket):

const ele2 = <HTMLCanvasElement>document.getElementById('some-id');

这种写法可能在 tsx 文件中眼花,因为标签太多了。

强转类型

一般是这样用的:

const ele2 = <HTMLCanvasElement>document.getElementById('some-id');

但是我们可以:

指鹿为马

不管看多少次还是感觉很变态(不是)。

let AString = 'I am a string!!!';
const BNum = (AString as any) as number;
// do it with two angle-bracket syntax
const CNum = <number><any>Astring;

声明任意输入的函数

这和写 any 差别不大,所以少用:

type anyInputFunc = (...args: any[]) => void

枚举与元组

这两个在 vanilla JavaScript 中是不出现的。

枚举状态号:

enum StatusCode {
    OK = 0
    WARN
    ERROR
}

if (someThingWrong) {
    return StatusCode.ERROR;
} else {
    return StatusCode.OK;
}

元组:

暂时主要只想到在 useState 中使用,因为它恰好是返回一个元组。

其实可以不需要,类型推断大部分时候都足够了。

const myStat: [IProps, React.Dispatch<React.setStateAction<IProps>>] = useState<IProps>({});

我基本只有在偶尔需要将 setter 作为参数传递出去的时候才进行声明,当然传递出去不是好事,因为状态应该是组件的,setter 应该也只通过自己访问。

要做更好设计,可以考虑同时结合 useContextuseRef 钩子。其中 Ref 钩子范用性很强,不止可以绑定 DOM 元素。

模块声明

默认配置好的 tsconfig.json 会自动解析目录下的所有 *.d.ts 文件。

d.ts 文件中只要有 exportimport 语句,就会被识别为一个模块。

模块非全局可见,要使用必须导入。

// module example
import SomeType from 'some-where';

export declare namespace MyNamespace {
    let varName: string;
    const cvName: string;
   	function foo(someVar: string): void;
    interface Laap {
    	prop: string
    }
}

但是有时想使用全局模块,但是不得不导入其他文件的类型声明。我们可以用类似异步的方法导入。注意 d.ts 永远不会被编译出结果代码,所以无论怎样书写都行(不是)。

在这里,实际并不是异步导入。

// global example

// access Items.item everywhere through your project
declare namespace Items {
    const item: import('types').ItemProp;
}

多类型与判断

我看 TS 文档,感觉它主要是在强调它很强(我很强,非常强,比你们都强)。这说的不是类型的强,而是它具有足够强大的类型推断能力。因此你可以放心的将很多事情交给他。

比如 TS 可以很方便的通过分支上下文推断具体类型:

type NumAndStr = number | string;
let var1: NumAndStr = 1;

if (typeof var1 === 'string') {
    // become string
    const foo = var1.split('/');
} else {
    const foo2 = var1 + 1;
}

typeof 基本只能推断出基本类型。要推断构造类型,使用 instanceof 即可,TS 也能准确的推断出来:

type dateObj = Date | null;

let var1: dateObj = new Date();

if (var1 instanceof Date) {
    // Date type
} else {
    // null
}

如果是更多类型,可以简单写一个 switch

此外还有函数重载等等。在我短暂的一生中,基本没有遇到需要使用函数重载的情况,因为太菜不需要做各种兼容。

与 React 使用

与 React 使用变为有点复杂的事情了,因为你可能同时要与浏览器类型与 React 类型打交道。浏览器发展到今天,类型声明已经非常惊人了。

即使是写一点简单的页面都感觉自己在和大项目打交道。

这些东西太多太杂。我的处理方式是首先书写数值,然后通过 IDE 推断出类型,然后再将推断出的类型提取出来。这在 IDE 中通过内置文档就能做到,毕竟基本大一点的项目类型声明写的还是舒服的。

如果还是有问题或者有疑问,那还是只能在网上查找相关文档或者解决方法。

或者 any。